Repository: ansible/ansible

Issue:
Permission error when loading postgresql_user module in Ubuntu and OL
##### ISSUE TYPE
- Bug Report
##### ANSIBLE VERSION

git bisect run shows this was likely introduced by 6cb8fdeaf2e9c7c787fa42dcf92a4bc36913b365
##### CONFIGURATION

No changes in ansible configuration to speak of.
##### OS / ENVIRONMENT

This has been observed in Ubuntu 12.04 & 14.04 and OL 6.7 and 7.2.
postgresql and active server need to be running on instance.
##### SUMMARY

postgresql_user module usage fails in Ubuntu and OL running a recent version of ansible from devel.
##### STEPS TO REPRODUCE

Assuming you have a properly configured local instance of postgres running, try the following play:

```
- hosts: localhost
  tasks: 
    - postgresql_user:
        name: username
        password: password
      sudo: True
      sudo_user: postgres
```
##### EXPECTED RESULTS

Successful creation of the user.
##### ACTUAL RESULTS

Failure to launch the prostgresql_user module.

```
TASK [postgresql_user] *********************************************************
task path: /tmp/repro/play.yml:3
Using module file /root/ansible/lib/ansible/modules/core/database/postgresql/postgresql_user.py
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: root
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /tmp/ansible-tmp-1466530323.97-248431454773543 `" && echo ansible-tmp-1466530323.97-248431454773543="` echo /tmp/ansible-tmp-1466530323.97-248431454773543 `" ) && sleep 0'
<127.0.0.1> PUT /tmp/tmpR2EhHZ TO /tmp/ansible-tmp-1466530323.97-248431454773543/postgresql_user.py
<127.0.0.1> EXEC /bin/sh -c 'find /tmp/ansible-tmp-1466530323.97-248431454773543/ -exec setfacl -m u:postgres:rx '"'"'{}'"'"' '"'"';'"'"' && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'sudo -H -S -n -u postgres /bin/sh -c '"'"'echo BECOME-SUCCESS-mdwgnyaovobfozffglbnqnuzqxvwqbhz; /usr/bin/python /tmp/ansible-tmp-1466530323.97-248431454773543/postgresql_user.py'"'"' && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /tmp/ansible-tmp-1466530323.97-248431454773543/ > /dev/null 2>&1 && sleep 0'
fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_name": "postgresql_user"}, "module_stderr": "/usr/bin/python: can't open file '/tmp/ansible-tmp-1466530323.97-248431454773543/postgresql_user.py': [Errno 13] Permission denied\n", "module_stdout": "", "msg": "MODULE FAILURE", "parsed": false}
```



Discussion:
can you run this with 
`ANSIBLE_KEEP_REMOTE_FILES=1` and post the generated module (like /tmp/ansible-tmp-1466530323.97-248431454773543/postgresql_user.py, but the one from the new run)

And output of `getfacl /tmp/path_to_the_generated_module.py`

connecting as root to host?
then sudo to postgres

could the

```
<127.0.0.1> EXEC /bin/sh -c 'find /tmp/ansible-tmp-1466530323.97-248431454773543/ -exec setfacl -m u:postgres:rx '"'"'{}'"'"' '"'"';'"'"' && sleep 0'
```

be missing the /tmp/ansible-tmp-1466530323.97-248431454773543/ directory itself? That would
potentially prevent the sudoed-as-postgres-user command below from reading the contents of the dir. 

```
<127.0.0.1> EXEC /bin/sh -c 'sudo -H -S -n -u postgres /bin/sh -c '"'"'echo BECOME-SUCCESS-mdwgnyaovobfozffglbnqnuzqxvwqbhz; /usr/bin/python /tmp/ansible-tmp-1466530323.97-248431454773543/postgresql_user.py'"'"' && sleep 0'
```

/dev/null 2>&1 && sleep 0'```

from HEAD :

```
# file: postgresql_user.py
# owner: root
# group: root
user::rw-
group::r--
other::r--
```

from 82b978e186b99aed0952bd3d72a07f02b968601f :

```
# file: postgresql_user.py
# owner: postgres
# group: root
user::rwx
group::r--
other::r--
```

Looks like the 'acl' package must be installed before this works.

See https://gist.github.com/alikins/a95e22c75415ebc037deac823becf0e0

Note that if I go back to the commit before 6cb8fdeaf2e9c7c787fa42dcf92a4bc36913b365 , that playbook still fails for me with different errors.

See https://gist.github.com/alikins/28f70f0b299ef76ef76a069110f6f237

But that's if running ansible-playbook as user (vagrant) and not root.

Running ansible-playbook as root works:

https://gist.github.com/alikins/5815e8a16a7ee617cd143b8604940cb9

Right, the playbook was being run as root to begin with and sorry for not stating that earlier.  The `acl` requirement should have been obvious since the change involved `setfacl`, but I'm a little confused why this worked before the change when it wasn't installed to begin with.

Not sure yet, I suspect https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/__init__.py#L343-L366
is involved, and maybe https://github.com/ansible/ansible/commit/8c7ceaab816652cef68a25342d4ba51821d6500c

(The latter would be after 'from 82b978e :')

Not sure what the interaction is, but it seems like sometime before https://github.com/ansible/ansible/commit/6cb8fdeaf2e9c7c787fa42dcf92a4bc36913b365, the fallback when setfacl fails worked, and got the perms sorted out other ways.

And then after either https://github.com/ansible/ansible/commit/6cb8fdeaf2e9c7c787fa42dcf92a4bc36913b365 or after  
https://github.com/ansible/ansible/commit/8c7ceaab816652cef68a25342d4ba51821d6500c, that fallback stopped working.

Haven't bisected yet though.

after more bisecting, a tl;dr

it seems like 'acl' was not a requirement before https://github.com/ansible/ansible/commit/6cb8fdeaf2e9c7c787fa42dcf92a4bc36913b365

And with 'acl', 6cb8fdeaf2e9c7c787fa42dcf92a4bc36913b3 works, but fails without.

'acl' is not really meant to be a requirement, so while there is a workaround, this bug still needs to be resolved so it works without 'acl'

Tracked this down to find -exec \; not returning non-zero if the command being exec'd fails.  Changing ; to + will fix that but I don't know if it's portable enough.
- -exec with + is not in SUSv2: http://pubs.opengroup.org/onlinepubs/7990989775/xcu/find.html
- It is in SUSv3: http://pubs.opengroup.org/onlinepubs/009695399/utilities/find.html
- A web search turns up this page: http://www.in-ulm.de/~mascheck/various/find/#xargs which lists when various find implementations gained -exec +.  OpenBSD find may not have -exec + but it also may not have setfacl.  GNU findutils gained + in 2005 with version 4.2.12.  RHEL5 has version 4.2.27.

As long as find exits with an error when using -exec + instead of the silent failure behaviour of -exec setfacl ; this should at least let us fallback to the chown code instead of getting permission denied later.  So if most *nixes support -exec + I think it's worthwhile to do.


Resolving patch:
diff --git a/lib/ansible/plugins/shell/__init__.py b/lib/ansible/plugins/shell/__init__.py
--- a/lib/ansible/plugins/shell/__init__.py
+++ b/lib/ansible/plugins/shell/__init__.py
@@ -93,7 +93,7 @@ def set_user_facl(self, path, user, mode, recursive=True):
 
         cmd = ['setfacl', '-m', 'u:%s:%s' % (user, mode)]
         if recursive:
-            cmd = ['find', path, '-exec'] + cmd + ["'{}'", "';'"]
+            cmd = ['find', path, '-exec'] + cmd + ["'{}'", "'+'"]
         else:
             cmd.append(path)
 


Test patch: