Repository: ansible/ansible-modules-core

Issue:
File mode 0755 fails for a tar in `unarchive`
##### ISSUE TYPE
- Bug Report
##### COMPONENT NAME

Module: `unarchive`
##### ANSIBLE VERSION

<!--- Paste verbatim output from “ansible --version” between quotes below -->

```
ansible 2.1.0.0
```
##### CONFIGURATION

N/A
##### OS / ENVIRONMENT

N/A
##### SUMMARY

`unarchive` fails with a `mode` of `0755`.
##### STEPS TO REPRODUCE

Create a `tar.gz` file (or any format that will be processed by [`TgzArchive`](https://github.com/ansible/ansible-modules-core/blob/devel/files/unarchive.py#L537)):

```
$ mkdir mydir
$ tar -czf mydir.tar.gz mydir
```

Use a playbook similar to the following (the important bit is the file mode):

```
- hosts: localhost

  tasks:
  - name: extract dir
    unarchive:
      src: "./mydir.tar.gz"
      dest: "./"
      mode: 0755
```
##### EXPECTED RESULTS

I would expect the playbook to run without error.
##### ACTUAL RESULTS

<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->

```
$ ansible-playbook myplaybook.yml 

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

TASK [setup] *******************************************************************
ok: [localhost]

TASK [extract dir] *************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "dest": "./", "failed": true, "gid": 1000, "group": "jesse", "handler": "TgzArchive", "mode": "0775", "msg": "Unexpected error when accessing exploded file: [Errno 2] No such file or directory: './mydir'", "owner": "jesse", "size": 4096, "src": "/home/jesse/.ansible/tmp/ansible-tmp-1467149922.64-77975041845860/source", "state": "directory", "uid": 1000}

NO MORE HOSTS LEFT *************************************************************
    to retry, use: --limit @myplaybook.retry

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1
```

Running the same playbook, but replacing the file mode `0755` with `0777` runs without error:

```
$ ansible-playbook myplaybook.yml 

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

TASK [setup] *******************************************************************
ok: [localhost]

TASK [extract dir] *************************************************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0
```

The error message in itself does not tell us a lot, but if we add some debug traces ([`check_results`](https://github.com/ansible/ansible-modules-core/blob/devel/files/unarchive.py#L778)), we see that the following `tar` command is being executed:

```
/bin/tar -C "./" -dz --mode="493" -f "/home/jesse/.ansible/tmp/ansible-tmp-1467150531.52-232348981801230/source"
```

and that `tar` is not happy about it:

```
/bin/tar: Invalid mode given on option
/bin/tar: Error is not recoverable: exiting now
```

The integer `493` passed to tar as a mode happens to be the decimal representation of `0755`. Tar complains because this is an invalid octal number for the `mode`. The file mode is being passed as decimal because it is passed to `tar` after casting it directly to a string (i.e. results in a decimal representation) in [`is_unarchived`](https://github.com/ansible/ansible-modules-core/blob/devel/files/unarchive.py#L585) and [`unarchive`](https://github.com/ansible/ansible-modules-core/blob/devel/files/unarchive.py#L628).

However, it looks like `tar` does not even care about `--mode` on `--diff` or `--extract` (emphasis is mine):

> `--mode=permissions'
> **When adding files to an archive**, tar will use permissions for the archive members, rather than the permissions from the files.

My understanding is that passing this parameter should not have an impact on the files handled by `-d` or `-x`. This would explain why the issue was hard to encounter; only a file mode that would yield an invalid octal number _after_ a conversion to a decimal number would make it fail. It does not have an effect on the final mode set.

Is there a particular reason for passing `--mode` when calling `tar -x` or `tar -d`?

If this is indeed a bug and I am not misconfiguring my playbook in some way, the workaround is rather simple -- using a symbolic representation for the file mode works like a charm.

If possible, I would be pleased to work on a PR to fix the issue in order to get involved in the project and its contribution process.



Discussion:
I think it works if you make your mode a string.
And personally I think Ansible should give a warning if it is not a string, rather than support string, octal and decimal mode.


Resolving patch:
diff --git a/files/unarchive.py b/files/unarchive.py
--- a/files/unarchive.py
+++ b/files/unarchive.py
@@ -614,8 +614,6 @@ def is_unarchived(self):
             cmd.append('--owner=' + quote(self.file_args['owner']))
         if self.file_args['group']:
             cmd.append('--group=' + quote(self.file_args['group']))
-        if self.file_args['mode']:
-            cmd.append('--mode=' + quote(self.file_args['mode']))
         if self.module.params['keep_newer']:
             cmd.append('--keep-newer-files')
         if self.excludes:
@@ -663,8 +661,6 @@ def unarchive(self):
             cmd.append('--owner=' + quote(self.file_args['owner']))
         if self.file_args['group']:
             cmd.append('--group=' + quote(self.file_args['group']))
-        if self.file_args['mode']:
-            cmd.append('--mode=' + quote(self.file_args['mode']))
         if self.module.params['keep_newer']:
             cmd.append('--keep-newer-files')
         if self.excludes:


Test patch: