How do I recursively set directory/file permissions

The documentation for file says there is an option to do this:
http://ansible.cc/docs/modules.html#file

In my playbook I have:

file: path=/pathto/somedirectory owner=someowner group=somegroup state=directory recurse=yes

But it only sets owner/group for the TLD. So recurse did not work. I tried putting it before the “state=” statement and then before the “owner” statement but it still didn’t work. Looking in /usr/share/ansible/file it doesn’t show that option in the explanations.

So how can I do this?

There was just, as in today, a thread about this on the ML. See:

https://groups.google.com/forum/?fromgroups=#!topic/ansible-project/Ek6wIZR-tfQ

Romeo

Yes, Michael asked me to file a bug on it. I haven’t gotten around to creating a small test case yet though.

-scott

Thanks for the link. As long as I know it’s supposed to work I’ll wait for the fix I guess.

Is there another way to do this in playbooks?

shell: chown -R user foo && chmod -R 644 foo

So, a year and a half and several releases later, still not working? It would be really nice not to have to set directory permissions in a separate step.

Perhaps I spoke too soon. I found that if I create a directory tree in one “file:” task:

file: path=/top/dir/path/to/directory owner=user group=mygroup mode=755 state=directory recurse=yes

only “directory” has the correct owner and permissions. But if I subsequently call file again and just specify the entry point to my tree:

file: path=/top/dir/path owner=user group=mygroup mode=755 state=directory recurse=yes

then the permissions and owner from “path” down were correctly set. And really, after thinking about it a bit, I wouldn’t have wanted the first step to have set everything as that would have changed the permissions and owner on the upper level directories too, which is not what I wanted. Perhaps the module needs a “chdir” argument to move to the top directory (chdir=/top/dir in my example), and then “path” can specify a relative path instead of an absolute path. That way recursive permissions can be set from that point down.

Recursive directory setting is almost never something you want to do.

Assume “/foo/bar” doesn’t exist and the directory specified is “/foo/bar/baz/gulp/gorp”

The permissions on the leaf node may be good choices, but what should the intermediate permissions be set as? Do they come from bar or gorp?"

As such, when doing recursive copying, setting permissions on each leaf node makes sense.

Otherwise, just call chmod -R, and it will do what it normally does.

" But if I subsequently call file again and just specify the entry point to my tree"

I would hope the module didn’t act differently on subsequent runs. Not sure what I want resolution to be, but filing a bug there is worthwhile.

No, it worked as it should have each time. The first time I called it with the full path to the bottom leaf directory and that created all of the intermediate directories. The second time I called it I specified just the entry point to the directory tree and that change the owner and permissions of the intermediate directories from that point down to the bottom leaf.
Still, it would be more convenient if I could specify the entry point and the bottom leaf in one call instead of splitting this across two calls. And the advantage of using the “file” module each time instead of using a “shell” task is that the file task can report whether a change was made or not while a shell task will always report “changed”.

The general situation is that change detection on a tree of 5000 files would be remarkably slow. People think they want that, they do not.

AFAIK chmod/chown as shell tools do not have a return code option, settable by flag or otherwise that returns whether anything was changed. If they did, we would be able to shell out to it and you could use a “changed_when” based on the return code result.

Doing it in python with 5000 (+) stat calls would not be pretty.

Excerpts from Michael DeHaan's message of 2014-07-30 07:51:22 -0400:

The general situation is that change detection on a tree of 5000 files
would be remarkably slow. People think they want that, they do not.

Just though I'd point out that there is a pull request for this:
https://github.com/ansible/ansible/pull/5220

Slow may very well be a concern, though.

AFAIK chmod/chown as shell tools do not have a return code option, settable
by flag or otherwise that returns whether anything was changed. If they
did, we would be able to shell out to it and you could use a "changed_when"
based on the return code result.

GNU chmod/chown actually *do* have something like this:

    -c, --changes like verbose but report only when a change is made

If you combine this with '-R' and '-f' (for silent), then if there is anything
in stdout at all, you know a change has been made.

I've been using it like so while waiting for the aforementioned pull
request:

      - command: chmod -cfR u+X,g+X,o-w,o+X "{{ my_dir }}"
        register: perm_change
        changed_when: perm_change.stdout

Not ideal, in my opinion, but it works and could perhaps be used in
set_mode_if_different() method in the AnsibleModule class. Not sure how
to deal with check mode using that method, though.

So the idea of backing it by chmod with -c sounds great but we’d need an option for when it was non-GNU, really it would need to autodetect and use the legacy path.

Generally I don’t like including alternate code paths, but this would mainly be for recursive=yes and in that case we could have a caveat about behavior on non-GNU systems if need be.