Repository: ansible/ansible

Issue:
File mode being set incorrectly
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and devel branch are affected too.
Always add information AFTER of these html comments.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
 - Bug Report

##### COMPONENT NAME
<!---
Insert below this comment the name of the module, plugin, task or feature.
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path
-->
file

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.5.0
  config file = /home/ahmad/projects/playbooks/ansible.cfg
  configured module search path = [u'/home/ahmad/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/ahmad/.virtualenvs/playbooks/local/lib/python2.7/site-packages/ansible
  executable location = /home/ahmad/.virtualenvs/playbooks/bin/ansible
  python version = 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609]
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
```
ANSIBLE_NOCOWS(env: ANSIBLE_NOCOWS) = True
DEFAULT_ASK_SUDO_PASS(/home/ahmad/projects/playbooks/ansible.cfg) = True
DEFAULT_HOST_LIST(/home/ahmad/projects/playbooks/ansible.cfg) = [u'/home/ahmad/projects/playbooks/hosts']
```

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
Client: Ubuntu 16.04
Affected host: FreeBSD 11.0-RELEASE-p1

##### SUMMARY
<!--- Explain the problem briefly -->

Octal file mode of '1777' on a directory is being applied incorrectly

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: Set permissions on network share
  file:
    path: /storage/share
    mode: 1777
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->

Expected perms, as applied manually:
```
[ahmad@amthree /storage]$ sudo chmod 1777 share
drwxrwxrwt  2 root  wheel     2B Mar  5  2017 .
drwxr-xr-x  5 root  wheel     5B Mar  5  2017 ..

```

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
Actual perms (applied by Ansible):

```
[ahmad@amthree /storage]$ ls -lah
total 35
drwxr-xr-x   5 root  wheel     5B Mar  5  2017 .
drwxr-xr-x  19 root  wheel    26B Mar 24 16:54 ..
...
d-wxrwS--t   2 root  wheel     2B Mar  5  2017 share
```

<!--- Paste verbatim command output between quotes below -->
```
TASK [double : Set permissions on network share] *******************************************************************************************************************************************************************
changed: [amthree] => {"changed": true, "gid": 0, "group": "wheel", "mode": "03361", "owner": "root", "path": "/storage/share", "size": 2, "state": "directory", "uid": 0}
```



Discussion:
Files identified in the description:
* [lib/ansible/modules/files/file.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/files/file.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
Looks like somehow `mode: 1777` is being transposed into `"mode": "03361"`

Entering the mode as a string ( `mode: "1777"`) makes things work as expected:
```TASK [double : Set permissions on network share] *******************************************************************************************************************************************************************
changed: [amthree] => {"changed": true, "gid": 0, "group": "wheel", "mode": "01777", "owner": "root", "path": "/storage/share", "size": 2, "state": "directory", "uid": 0}
@anoother could you run that playbook with ansible-playbook adding the '-vvv' and '--diff' options?


@anoother The controller is running Ubuntu 16.04 and python2.7?

For the remote affected host, FreeBSD 11.0-RELEASE-p1 and which python version?
pinging @abadger 
You need to either signify that's octal to yaml by using a leading zero or
quite it so that Ansible receives it as a string.

On Mon, Mar 26, 2018, 6:43 AM Adrian Likins <notifications@github.com>
wrote:

> pinging @abadger <https://github.com/abadger>
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/ansible/ansible/issues/37875#issuecomment-376170229>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAMxWixXxg0a96MM7xBc8kRwuw2n37zMks5tiPBrgaJpZM4S50bI>
> .
>

*quote it

>

The need for a leading zero is described in the docs: http://docs.ansible.com/ansible/latest/file_module.html#options  although I see that it could be clearer for non-programmers.  The docs tell you that you need an octal number and that you need the leading zero but don't explicitly draw the connection that it's treated as octal with the leading zero and treated as a decimal number without.

Resolving patch:
diff --git a/lib/ansible/utils/module_docs_fragments/files.py b/lib/ansible/utils/module_docs_fragments/files.py
--- a/lib/ansible/utils/module_docs_fragments/files.py
+++ b/lib/ansible/utils/module_docs_fragments/files.py
@@ -23,9 +23,12 @@ class ModuleDocFragment(object):
 options:
   mode:
     description:
-      - Mode the file or directory should be. For those used to I(/usr/bin/chmod) remember that modes are actually octal numbers (like C(0644) or C(01777)).
-        Leaving off the leading zero will likely have unexpected results.
-        As of version 1.8, the mode may be specified as a symbolic mode (for example, C(u+rwx) or C(u=rw,g=r,o=r)).
+      - "Mode the file or directory should be. For those used to I(/usr/bin/chmod) remember that modes are actually octal numbers.
+        You must either specify the leading zero so that Ansible's YAML parser knows it is an octal
+        number (like C(0644) or C(01777)) or quote it (like C('644') or C('0644') so Ansible
+        receives a string and can do its own conversion from string into number.  Giving Ansible a number
+        without following one of these rules will end up with a decimal number which will have unexpected results.
+        As of version 1.8, the mode may be specified as a symbolic mode (for example, C(u+rwx) or C(u=rw,g=r,o=r))."
   owner:
     description:
       - Name of the user that should own the file/directory, as would be fed to I(chown).


Test patch: