Repository: ansible/ansible

Issue:
Using the filesystem module with resizefs=yes on an XFS filesystem fails
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
filesystem module (xfs tasks)

##### ANSIBLE VERSION
```
ansible 2.2.1.0
ansible 2.3.0.0
```

##### CONFIGURATION

/etc/ansible/ansible.cfg
```
[privilege_escalation]
become=True
#become_method=sudo
become_user=root
#become_ask_pass=False
pipelining = True

#if True, make ansible use scp if the connection type is ssh
#(default is sftp)
scp_if_ssh = True
```

##### OS / ENVIRONMENT
RHEL7.3

##### SUMMARY
Using the filesystem module with resizefs=yes on an XFS filesystem fails with 
{"changed": false, "err": "/sbin/xfs_info: line 25: xfs_growfs: command not found\n", "failed": true, "msg": "Failed to get block count and block size of /dev/vg00/test_lv with /sbin/xfs_info", "rc": 127}
 Note works fine for ext3/4

##### STEPS TO REPRODUCE
Reproducable everytime that a filesystem resize is attempted

```
    - name: Manage / resize test_lv filesystem
      filesystem: fstype={{ item.fstype | default('xfs') }} dev="/dev/vg00/test_lv" resizefs=yes
```

Workaround is to add environment & path to the task to include the path to where xfs_growfs is (/usr/sbin), OR to copy xfs_growfs to /bin
eg

```
    - name: Manage / resize test_lv filesystem
      environment:
         PATH: "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
      filesystem: fstype={{ item.fstype | default('xfs') }} dev="/dev/vg00/test_lv" resizefs=yes
```

##### EXPECTED RESULTS
Changed ( / Success)

##### ACTUAL RESULTS
```
TASK [rhel7 : Manage / resize /dev/vg00/test_lv filesystem] *************
task path: /home/ansible/pdev/new/RHEL7_Build/linkedgits/ansible_task_library/lvol_task.yml:59
Using module file /usr/lib/python2.6/site-packages/ansible/modules/extras/system/filesystem.py
<testserver> ESTABLISH SSH CONNECTION FOR USER: None
<testserver> SSH: EXEC ssh -vvv -o ControlMaster=auto -o ControlPersist=60s -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/ansible/.ansible/cp/ansible-ssh-%h-%p-%r testserver '/bin/sh -c '"'"'sudo -H -S -n -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-jhkejhgrkyphvifhnucxjdsksmjpgdff; /usr/bin/python'"'"'"'"'"'"'"'"' && sleep 0'"'"''
fatal: [testserver]: FAILED! => {
    "changed": false,
    "err": "/sbin/xfs_info: line 25: xfs_growfs: command not found\n",
    "failed": true,
    "invocation": {
        "module_args": {
            "dev": "/dev/vg00/test_lv",
            "force": false,
            "fstype": "xfs",
            "opts": null,
            "resizefs": true
        },
        "module_name": "filesystem"
    },
    "msg": "Failed to get block count and block size of /dev/vg00/test_lv with /sbin/xfs_info",
    "rc": 127
}
```


Discussion:
cc @abulimov
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@pdev77 could you check the PATH variable of the remote user ? Use something like `ansible testserver -m shell -a 'echo $PATH'`. I guess `ansible testserver -m command -a 'xfs_info -V'` will fail too.

`xfs_info` is a [bash script](https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git/tree/growfs/xfs_info.sh) located in `/usr/sbin/` (`/sbin` is a symlink to `/usr/sbin/`) which calls `xfs_growfs` command. It seems ansible is able to find `xfs_info` because `/sbin` path is [hardcoded](https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/basic.py#L2024) in `get_bin_path`, then `xfs_growfs` isn't found because neither `/sbin` nor `/usr/sbin` are in the `PATH` environment variable.

`xfs_growfs -n` could be used directly instead of `xfs_info`, (the [man page](https://linux.die.net/man/8/xfs_info) states that: _xfs_info is equivalent to invoking xfs_growfs with the -n option_) but I am not sure if it would be an improvement.
Hi yes you are right :

```
[ansible@server ]$ ansible testserver -m shell -a 'echo $PATH'
testserver | SUCCESS | rc=0 >>
/usr/local/bin:/usr/bin

[ansible@server ]$ ansible testserver -m command -a 'xfs_info -V'
testserver | FAILED | rc=2 >>
[Errno 2] No such file or directory
```



Same configuration, same problem.

Tested with 
```
RH 7.1 
RH 7.3 
```

Tested with ansible versions :
```
2.2.1.0
2.3.1.0
```

For me, the workaround specifying the PATH doesn't work:



```
- name: Create filesystem 
  environment:
      PATH: "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
  filesystem: fstype={{ es_fstype }} dev=/dev/{{es_vg}}/{{es_lv}} resizefs=yes force=no 
```


```

fatal: [maastest]: FAILED! => {
    "changed": false, 
    "err": "xfs_info: /dev/vgelastic/lv_elastic_data is not a mounted XFS filesystem\n", 
    "failed": true, 
    "invocation": {
        "module_args": {
            "dev": "/dev/vgelastic/lv_elastic_data", 
            "force": false, 
            "fstype": "xfs", 
            "opts": null, 
            "resizefs": true
        }, 
        "module_name": "filesystem"
    }, 
    "msg": "Failed to get block count and block size of /dev/vgelastic/lv_elastic_data with /sbin/xfs_info", 
    "rc": 1
}

```

Resolving patch:
diff --git a/lib/ansible/modules/system/filesystem.py b/lib/ansible/modules/system/filesystem.py
--- a/lib/ansible/modules/system/filesystem.py
+++ b/lib/ansible/modules/system/filesystem.py
@@ -96,17 +96,17 @@ def _get_fs_size(fssize_cmd, dev, module):
                     break
         else:
             module.fail_json(msg="Failed to get block count and block size of %s with %s" % (dev, cmd), rc=rc, err=err )
-    elif 'xfs_info' == fssize_cmd:
+    elif 'xfs_growfs' == fssize_cmd:
         # Get Block count and Block size
-        rc, size, err = module.run_command("%s %s" % (cmd, dev))
+        rc, size, err = module.run_command([cmd, '-n', dev])
         if rc == 0:
             for line in size.splitlines():
                 col = line.split('=')
                 if col[0].strip() == 'data':
                     if col[1].strip() != 'bsize':
-                        module.fail_json(msg='Unexpected output format from xfs_info (could not locate "bsize")')
+                        module.fail_json(msg='Unexpected output format from xfs_growfs (could not locate "bsize")')
                     if col[2].split()[1] != 'blocks':
-                        module.fail_json(msg='Unexpected output format from xfs_info (could not locate "blocks")')
+                        module.fail_json(msg='Unexpected output format from xfs_growfs (could not locate "blocks")')
                     block_size = int(col[2].split()[0])
                     block_count = int(col[3].split(',')[0])
                     break
@@ -176,7 +176,7 @@ def main():
             'grow' : 'xfs_growfs',
             'grow_flag' : None,
             'force_flag' : '-f',
-            'fsinfo': 'xfs_info',
+            'fsinfo': 'xfs_growfs',
         },
         'btrfs' : {
             'mkfs' : 'mkfs.btrfs',


Test patch: