We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
filesystem does not support multiple devices (on btrfs f.e.) #3338
Moved from: https://github.com/ansible/ansible-modules-extras/issues/3338

##### ISSUE TYPE
- Feature Idea
 - ~~Bug Report~~

##### COMPONENT NAME
`filesystem` module

##### ANSIBLE VERSION
```
ansible 2.1.2.0
  config file = /home/pasha/Projects/Ansible.cfg/ansible.cfg
  configured module search path = ['modules/']
```

##### CONFIGURATION
Does not have sence

##### OS / ENVIRONMENT
Fedora repos

##### SUMMARY

Task:
```
- name: Create btrfs filesystem
  filesystem: fstype=btrfs dev='/dev/mapper/centos-home' opts='--label srv'
```
work as expected, but:
```
- name: Create btrfs filesystem
  filesystem: fstype=btrfs dev='/dev/sda3 /dev/sdb' opts='-d single --label srv'
```
Produce error: 
```
**Device /dev/sda3 /dev/sdb not found.**
```

##### EXPECTED RESULTS
`Btrfs` (and some other like `zfs` too) allow create filesystems across multiple devices - https://btrfs.wiki.kernel.org/index.php/Using_Btrfs_with_Multiple_Devices

So, it seams reasonable make `dev` parameter the list type or just allow pass any string.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/ansible/modules/system/filesystem.py`
Content:
```
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 
4 # (c) 2013, Alexander Bulimov <lazywolf0@gmail.com>
5 #
6 # This file is part of Ansible
7 #
8 # Ansible is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # Ansible is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
20 
21 ANSIBLE_METADATA = {'status': ['preview'],
22                     'supported_by': 'community',
23                     'version': '1.0'}
24 
25 DOCUMENTATION = '''
26 ---
27 author: "Alexander Bulimov (@abulimov)"
28 module: filesystem
29 short_description: Makes file system on block device
30 description:
31   - This module creates file system.
32 version_added: "1.2"
33 options:
34   fstype:
35     description:
36     - File System type to be created.
37     - reiserfs support was added in 2.2.
38     required: true
39   dev:
40     description:
41     - Target block device.
42     required: true
43   force:
44     choices: [ "yes", "no" ]
45     default: "no"
46     description:
47     - If yes, allows to create new filesystem on devices that already has filesystem.
48     required: false
49   resizefs:
50     choices: [ "yes", "no" ]
51     default: "no"
52     description:
53     - If yes, if the block device and filessytem size differ, grow the filesystem into the space. Note, XFS Will only grow if mounted.
54     required: false
55     version_added: "2.0"
56   opts:
57     description:
58     - List of options to be passed to mkfs command.
59 notes:
60   - uses mkfs command
61 '''
62 
63 EXAMPLES = '''
64 # Create a ext2 filesystem on /dev/sdb1.
65 - filesystem:
66     fstype: ext2
67     dev: /dev/sdb1
68 
69 # Create a ext4 filesystem on /dev/sdb1 and check disk blocks.
70 - filesystem:
71     fstype: ext4
72     dev: /dev/sdb1
73     opts: -cc
74 '''
75 
76 def _get_dev_size(dev, module):
77     """ Return size in bytes of device. Returns int """
78     blockdev_cmd = module.get_bin_path("blockdev", required=True)
79     rc, devsize_in_bytes, err = module.run_command("%s %s %s" % (blockdev_cmd, "--getsize64", dev))
80     return int(devsize_in_bytes)
81 
82 
83 def _get_fs_size(fssize_cmd, dev, module):
84     """ Return size in bytes of filesystem on device. Returns int """
85     cmd = module.get_bin_path(fssize_cmd, required=True)
86     if 'tune2fs' == fssize_cmd:
87         # Get Block count and Block size
88         rc, size, err = module.run_command("%s %s %s" % (cmd, '-l', dev))
89         if rc == 0:
90             for line in size.splitlines():
91                 if 'Block count:' in line:
92                     block_count = int(line.split(':')[1].strip())
93                 elif 'Block size:' in line:
94                     block_size = int(line.split(':')[1].strip())
95                     break
96         else:
97             module.fail_json(msg="Failed to get block count and block size of %s with %s" % (dev, cmd), rc=rc, err=err )
98     elif 'xfs_info' == fssize_cmd:
99         # Get Block count and Block size
100         rc, size, err = module.run_command("%s %s" % (cmd, dev))
101         if rc == 0:
102             for line in size.splitlines():
103                 #if 'data' in line:
104                 if 'data ' in line:
105                     block_size = int(line.split('=')[2].split()[0])
106                     block_count = int(line.split('=')[3].split(',')[0])
107                     break
108         else:
109             module.fail_json(msg="Failed to get block count and block size of %s with %s" % (dev, cmd), rc=rc, err=err )
110     elif 'btrfs' == fssize_cmd:
111         #ToDo
112         # There is no way to get the blocksize and blockcount for btrfs filesystems
113         block_size = 1
114         block_count = 1
115 
116 
117     return block_size*block_count
118 
119 
120 def main():
121     module = AnsibleModule(
122         argument_spec = dict(
123             fstype=dict(required=True, aliases=['type']),
124             dev=dict(required=True, aliases=['device']),
125             opts=dict(),
126             force=dict(type='bool', default='no'),
127             resizefs=dict(type='bool', default='no'),
128         ),
129         supports_check_mode=True,
130     )
131 
132     # There is no "single command" to manipulate filesystems, so we map them all out and their options
133     fs_cmd_map = {
134         'ext2' : {
135             'mkfs' : 'mkfs.ext2',
136             'grow' : 'resize2fs',
137             'grow_flag' : None,
138             'force_flag' : '-F',
139             'fsinfo': 'tune2fs',
140         },
141         'ext3' : {
142             'mkfs' : 'mkfs.ext3',
143             'grow' : 'resize2fs',
144             'grow_flag' : None,
145             'force_flag' : '-F',
146             'fsinfo': 'tune2fs',
147         },
148         'ext4' : {
149             'mkfs' : 'mkfs.ext4',
150             'grow' : 'resize2fs',
151             'grow_flag' : None,
152             'force_flag' : '-F',
153             'fsinfo': 'tune2fs',
154         },
155         'reiserfs' : {
156             'mkfs' : 'mkfs.reiserfs',
157             'grow' : 'resize_reiserfs',
158             'grow_flag' : None,
159             'force_flag' : '-f',
160             'fsinfo': 'reiserfstune',
161         },
162         'ext4dev' : {
163             'mkfs' : 'mkfs.ext4',
164             'grow' : 'resize2fs',
165             'grow_flag' : None,
166             'force_flag' : '-F',
167             'fsinfo': 'tune2fs',
168         },
169         'xfs' : {
170             'mkfs' : 'mkfs.xfs',
171             'grow' : 'xfs_growfs',
172             'grow_flag' : None,
173             'force_flag' : '-f',
174             'fsinfo': 'xfs_info',
175         },
176         'btrfs' : {
177             'mkfs' : 'mkfs.btrfs',
178             'grow' : 'btrfs',
179             'grow_flag' : 'filesystem resize',
180             'force_flag' : '-f',
181             'fsinfo': 'btrfs',
182         }
183     }
184 
185     dev = module.params['dev']
186     fstype = module.params['fstype']
187     opts = module.params['opts']
188     force = module.boolean(module.params['force'])
189     resizefs = module.boolean(module.params['resizefs'])
190 
191     changed = False
192 
193     try:
194         _ = fs_cmd_map[fstype]
195     except KeyError:
196         module.exit_json(changed=False, msg="WARNING: module does not support this filesystem yet. %s" % fstype)
197 
198     mkfscmd = fs_cmd_map[fstype]['mkfs']
199     force_flag = fs_cmd_map[fstype]['force_flag']
200     growcmd = fs_cmd_map[fstype]['grow']
201     fssize_cmd = fs_cmd_map[fstype]['fsinfo']
202 
203     if not os.path.exists(dev):
204         module.fail_json(msg="Device %s not found."%dev)
205 
206     cmd = module.get_bin_path('blkid', required=True)
207 
208     rc,raw_fs,err = module.run_command("%s -c /dev/null -o value -s TYPE %s" % (cmd, dev))
209     fs = raw_fs.strip()
210 
211     if fs == fstype and resizefs == False and not force:
212         module.exit_json(changed=False)
213     elif fs == fstype and resizefs == True:
214         # Get dev and fs size and compare
215         devsize_in_bytes = _get_dev_size(dev, module)
216         fssize_in_bytes = _get_fs_size(fssize_cmd, dev, module)
217         if fssize_in_bytes < devsize_in_bytes:
218             fs_smaller = True
219         else:
220             fs_smaller = False
221 
222 
223         if module.check_mode and fs_smaller:
224             module.exit_json(changed=True, msg="Resizing filesystem %s on device %s" % (fstype,dev))
225         elif module.check_mode and not fs_smaller:
226             module.exit_json(changed=False, msg="%s filesystem is using the whole device %s" % (fstype, dev))
227         elif fs_smaller:
228             cmd = module.get_bin_path(growcmd, required=True)
229             rc,out,err = module.run_command("%s %s" % (cmd, dev))
230             # Sadly there is no easy way to determine if this has changed. For now, just say "true" and move on.
231             #  in the future, you would have to parse the output to determine this.
232             #  thankfully, these are safe operations if no change is made.
233             if rc == 0:
234                 module.exit_json(changed=True, msg=out)
235             else:
236                 module.fail_json(msg="Resizing filesystem %s on device '%s' failed"%(fstype,dev), rc=rc, err=err)
237         else:
238             module.exit_json(changed=False, msg="%s filesystem is using the whole device %s" % (fstype, dev))
239     elif fs and not force:
240         module.fail_json(msg="'%s' is already used as %s, use force=yes to overwrite"%(dev,fs), rc=rc, err=err)
241 
242     ### create fs
243 
244     if module.check_mode:
245         changed = True
246     else:
247         mkfs = module.get_bin_path(mkfscmd, required=True)
248         cmd = None
249 
250         if opts is None:
251             cmd = "%s %s '%s'" % (mkfs, force_flag, dev)
252         else:
253             cmd = "%s %s %s '%s'" % (mkfs, force_flag, opts, dev)
254         rc,_,err = module.run_command(cmd)
255         if rc == 0:
256             changed = True
257         else:
258             module.fail_json(msg="Creating filesystem %s on device '%s' failed"%(fstype,dev), rc=rc, err=err)
259 
260     module.exit_json(changed=changed)
261 
262 # import module snippets
263 from ansible.module_utils.basic import *
264 if __name__ == '__main__':
265     main()
266
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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
@@ -38,7 +38,7 @@
     required: true
   dev:
     description:
-    - Target block device.
+    - Target block device. Starting in 2.3 it can also take a list of devices for file systems that allow this.
     required: true
   force:
     choices: [ "yes", "no" ]
@@ -73,6 +73,9 @@
     opts: -cc
 '''
 
+import os
+from ansible.module_utils.basic import AnsibleModule
+
 def _get_dev_size(dev, module):
     """ Return size in bytes of device. Returns int """
     blockdev_cmd = module.get_bin_path("blockdev", required=True)
@@ -121,7 +124,7 @@
     module = AnsibleModule(
         argument_spec = dict(
             fstype=dict(required=True, aliases=['type']),
-            dev=dict(required=True, aliases=['device']),
+            dev=dict(required=True, aliases=['device'], type='list'),
             opts=dict(),
             force=dict(type='bool', default='no'),
             resizefs=dict(type='bool', default='no'),
@@ -200,12 +203,13 @@
     growcmd = fs_cmd_map[fstype]['grow']
     fssize_cmd = fs_cmd_map[fstype]['fsinfo']
 
-    if not os.path.exists(dev):
-        module.fail_json(msg="Device %s not found."%dev)
+    for device in dev:
+        if not os.path.exists(device):
+            module.fail_json(msg="Device %s not found." % device)
 
     cmd = module.get_bin_path('blkid', required=True)
 
-    rc,raw_fs,err = module.run_command("%s -c /dev/null -o value -s TYPE %s" % (cmd, dev))
+    rc,raw_fs,err = module.run_command("%s -c /dev/null -o value -s TYPE %s" % (cmd, ' '.join(dev)))
     fs = raw_fs.strip()
 
     if fs == fstype and resizefs == False and not force:
@@ -259,7 +263,5 @@
 
     module.exit_json(changed=changed)
 
-# import module snippets
-from ansible.module_utils.basic import *
 if __name__ == '__main__':
     main()

{"golden_diff": "diff --git a/lib/ansible/modules/system/filesystem.py b/lib/ansible/modules/system/filesystem.py\n--- a/lib/ansible/modules/system/filesystem.py\n+++ b/lib/ansible/modules/system/filesystem.py\n@@ -38,7 +38,7 @@\n     required: true\n   dev:\n     description:\n-    - Target block device.\n+    - Target block device. Starting in 2.3 it can also take a list of devices for file systems that allow this.\n     required: true\n   force:\n     choices: [ \"yes\", \"no\" ]\n@@ -73,6 +73,9 @@\n     opts: -cc\n '''\n \n+import os\n+from ansible.module_utils.basic import AnsibleModule\n+\n def _get_dev_size(dev, module):\n     \"\"\" Return size in bytes of device. Returns int \"\"\"\n     blockdev_cmd = module.get_bin_path(\"blockdev\", required=True)\n@@ -121,7 +124,7 @@\n     module = AnsibleModule(\n         argument_spec = dict(\n             fstype=dict(required=True, aliases=['type']),\n-            dev=dict(required=True, aliases=['device']),\n+            dev=dict(required=True, aliases=['device'], type='list'),\n             opts=dict(),\n             force=dict(type='bool', default='no'),\n             resizefs=dict(type='bool', default='no'),\n@@ -200,12 +203,13 @@\n     growcmd = fs_cmd_map[fstype]['grow']\n     fssize_cmd = fs_cmd_map[fstype]['fsinfo']\n \n-    if not os.path.exists(dev):\n-        module.fail_json(msg=\"Device %s not found.\"%dev)\n+    for device in dev:\n+        if not os.path.exists(device):\n+            module.fail_json(msg=\"Device %s not found.\" % device)\n \n     cmd = module.get_bin_path('blkid', required=True)\n \n-    rc,raw_fs,err = module.run_command(\"%s -c /dev/null -o value -s TYPE %s\" % (cmd, dev))\n+    rc,raw_fs,err = module.run_command(\"%s -c /dev/null -o value -s TYPE %s\" % (cmd, ' '.join(dev)))\n     fs = raw_fs.strip()\n \n     if fs == fstype and resizefs == False and not force:\n@@ -259,7 +263,5 @@\n \n     module.exit_json(changed=changed)\n \n-# import module snippets\n-from ansible.module_utils.basic import *\n if __name__ == '__main__':\n     main()\n", "issue": "filesystem does not support multiple devices (on btrfs f.e.) #3338\nMoved from: https://github.com/ansible/ansible-modules-extras/issues/3338\r\n\r\n##### ISSUE TYPE\r\n- Feature Idea\r\n - ~~Bug Report~~\r\n\r\n##### COMPONENT NAME\r\n`filesystem` module\r\n\r\n##### ANSIBLE VERSION\r\n```\r\nansible 2.1.2.0\r\n  config file = /home/pasha/Projects/Ansible.cfg/ansible.cfg\r\n  configured module search path = ['modules/']\r\n```\r\n\r\n##### CONFIGURATION\r\nDoes not have sence\r\n\r\n##### OS / ENVIRONMENT\r\nFedora repos\r\n\r\n##### SUMMARY\r\n\r\nTask:\r\n```\r\n- name: Create btrfs filesystem\r\n  filesystem: fstype=btrfs dev='/dev/mapper/centos-home' opts='--label srv'\r\n```\r\nwork as expected, but:\r\n```\r\n- name: Create btrfs filesystem\r\n  filesystem: fstype=btrfs dev='/dev/sda3 /dev/sdb' opts='-d single --label srv'\r\n```\r\nProduce error: \r\n```\r\n**Device /dev/sda3 /dev/sdb not found.**\r\n```\r\n\r\n##### EXPECTED RESULTS\r\n`Btrfs` (and some other like `zfs` too) allow create filesystems across multiple devices - https://btrfs.wiki.kernel.org/index.php/Using_Btrfs_with_Multiple_Devices\r\n\r\nSo, it seams reasonable make `dev` parameter the list type or just allow pass any string.\r\n\n", "before_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# (c) 2013, Alexander Bulimov <lazywolf0@gmail.com>\n#\n# This file is part of Ansible\n#\n# Ansible is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Ansible is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Ansible. If not, see <http://www.gnu.org/licenses/>.\n\nANSIBLE_METADATA = {'status': ['preview'],\n                    'supported_by': 'community',\n                    'version': '1.0'}\n\nDOCUMENTATION = '''\n---\nauthor: \"Alexander Bulimov (@abulimov)\"\nmodule: filesystem\nshort_description: Makes file system on block device\ndescription:\n  - This module creates file system.\nversion_added: \"1.2\"\noptions:\n  fstype:\n    description:\n    - File System type to be created.\n    - reiserfs support was added in 2.2.\n    required: true\n  dev:\n    description:\n    - Target block device.\n    required: true\n  force:\n    choices: [ \"yes\", \"no\" ]\n    default: \"no\"\n    description:\n    - If yes, allows to create new filesystem on devices that already has filesystem.\n    required: false\n  resizefs:\n    choices: [ \"yes\", \"no\" ]\n    default: \"no\"\n    description:\n    - If yes, if the block device and filessytem size differ, grow the filesystem into the space. Note, XFS Will only grow if mounted.\n    required: false\n    version_added: \"2.0\"\n  opts:\n    description:\n    - List of options to be passed to mkfs command.\nnotes:\n  - uses mkfs command\n'''\n\nEXAMPLES = '''\n# Create a ext2 filesystem on /dev/sdb1.\n- filesystem:\n    fstype: ext2\n    dev: /dev/sdb1\n\n# Create a ext4 filesystem on /dev/sdb1 and check disk blocks.\n- filesystem:\n    fstype: ext4\n    dev: /dev/sdb1\n    opts: -cc\n'''\n\ndef _get_dev_size(dev, module):\n    \"\"\" Return size in bytes of device. Returns int \"\"\"\n    blockdev_cmd = module.get_bin_path(\"blockdev\", required=True)\n    rc, devsize_in_bytes, err = module.run_command(\"%s %s %s\" % (blockdev_cmd, \"--getsize64\", dev))\n    return int(devsize_in_bytes)\n\n\ndef _get_fs_size(fssize_cmd, dev, module):\n    \"\"\" Return size in bytes of filesystem on device. Returns int \"\"\"\n    cmd = module.get_bin_path(fssize_cmd, required=True)\n    if 'tune2fs' == fssize_cmd:\n        # Get Block count and Block size\n        rc, size, err = module.run_command(\"%s %s %s\" % (cmd, '-l', dev))\n        if rc == 0:\n            for line in size.splitlines():\n                if 'Block count:' in line:\n                    block_count = int(line.split(':')[1].strip())\n                elif 'Block size:' in line:\n                    block_size = int(line.split(':')[1].strip())\n                    break\n        else:\n            module.fail_json(msg=\"Failed to get block count and block size of %s with %s\" % (dev, cmd), rc=rc, err=err )\n    elif 'xfs_info' == fssize_cmd:\n        # Get Block count and Block size\n        rc, size, err = module.run_command(\"%s %s\" % (cmd, dev))\n        if rc == 0:\n            for line in size.splitlines():\n                #if 'data' in line:\n                if 'data ' in line:\n                    block_size = int(line.split('=')[2].split()[0])\n                    block_count = int(line.split('=')[3].split(',')[0])\n                    break\n        else:\n            module.fail_json(msg=\"Failed to get block count and block size of %s with %s\" % (dev, cmd), rc=rc, err=err )\n    elif 'btrfs' == fssize_cmd:\n        #ToDo\n        # There is no way to get the blocksize and blockcount for btrfs filesystems\n        block_size = 1\n        block_count = 1\n\n\n    return block_size*block_count\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec = dict(\n            fstype=dict(required=True, aliases=['type']),\n            dev=dict(required=True, aliases=['device']),\n            opts=dict(),\n            force=dict(type='bool', default='no'),\n            resizefs=dict(type='bool', default='no'),\n        ),\n        supports_check_mode=True,\n    )\n\n    # There is no \"single command\" to manipulate filesystems, so we map them all out and their options\n    fs_cmd_map = {\n        'ext2' : {\n            'mkfs' : 'mkfs.ext2',\n            'grow' : 'resize2fs',\n            'grow_flag' : None,\n            'force_flag' : '-F',\n            'fsinfo': 'tune2fs',\n        },\n        'ext3' : {\n            'mkfs' : 'mkfs.ext3',\n            'grow' : 'resize2fs',\n            'grow_flag' : None,\n            'force_flag' : '-F',\n            'fsinfo': 'tune2fs',\n        },\n        'ext4' : {\n            'mkfs' : 'mkfs.ext4',\n            'grow' : 'resize2fs',\n            'grow_flag' : None,\n            'force_flag' : '-F',\n            'fsinfo': 'tune2fs',\n        },\n        'reiserfs' : {\n            'mkfs' : 'mkfs.reiserfs',\n            'grow' : 'resize_reiserfs',\n            'grow_flag' : None,\n            'force_flag' : '-f',\n            'fsinfo': 'reiserfstune',\n        },\n        'ext4dev' : {\n            'mkfs' : 'mkfs.ext4',\n            'grow' : 'resize2fs',\n            'grow_flag' : None,\n            'force_flag' : '-F',\n            'fsinfo': 'tune2fs',\n        },\n        'xfs' : {\n            'mkfs' : 'mkfs.xfs',\n            'grow' : 'xfs_growfs',\n            'grow_flag' : None,\n            'force_flag' : '-f',\n            'fsinfo': 'xfs_info',\n        },\n        'btrfs' : {\n            'mkfs' : 'mkfs.btrfs',\n            'grow' : 'btrfs',\n            'grow_flag' : 'filesystem resize',\n            'force_flag' : '-f',\n            'fsinfo': 'btrfs',\n        }\n    }\n\n    dev = module.params['dev']\n    fstype = module.params['fstype']\n    opts = module.params['opts']\n    force = module.boolean(module.params['force'])\n    resizefs = module.boolean(module.params['resizefs'])\n\n    changed = False\n\n    try:\n        _ = fs_cmd_map[fstype]\n    except KeyError:\n        module.exit_json(changed=False, msg=\"WARNING: module does not support this filesystem yet. %s\" % fstype)\n\n    mkfscmd = fs_cmd_map[fstype]['mkfs']\n    force_flag = fs_cmd_map[fstype]['force_flag']\n    growcmd = fs_cmd_map[fstype]['grow']\n    fssize_cmd = fs_cmd_map[fstype]['fsinfo']\n\n    if not os.path.exists(dev):\n        module.fail_json(msg=\"Device %s not found.\"%dev)\n\n    cmd = module.get_bin_path('blkid', required=True)\n\n    rc,raw_fs,err = module.run_command(\"%s -c /dev/null -o value -s TYPE %s\" % (cmd, dev))\n    fs = raw_fs.strip()\n\n    if fs == fstype and resizefs == False and not force:\n        module.exit_json(changed=False)\n    elif fs == fstype and resizefs == True:\n        # Get dev and fs size and compare\n        devsize_in_bytes = _get_dev_size(dev, module)\n        fssize_in_bytes = _get_fs_size(fssize_cmd, dev, module)\n        if fssize_in_bytes < devsize_in_bytes:\n            fs_smaller = True\n        else:\n            fs_smaller = False\n\n\n        if module.check_mode and fs_smaller:\n            module.exit_json(changed=True, msg=\"Resizing filesystem %s on device %s\" % (fstype,dev))\n        elif module.check_mode and not fs_smaller:\n            module.exit_json(changed=False, msg=\"%s filesystem is using the whole device %s\" % (fstype, dev))\n        elif fs_smaller:\n            cmd = module.get_bin_path(growcmd, required=True)\n            rc,out,err = module.run_command(\"%s %s\" % (cmd, dev))\n            # Sadly there is no easy way to determine if this has changed. For now, just say \"true\" and move on.\n            #  in the future, you would have to parse the output to determine this.\n            #  thankfully, these are safe operations if no change is made.\n            if rc == 0:\n                module.exit_json(changed=True, msg=out)\n            else:\n                module.fail_json(msg=\"Resizing filesystem %s on device '%s' failed\"%(fstype,dev), rc=rc, err=err)\n        else:\n            module.exit_json(changed=False, msg=\"%s filesystem is using the whole device %s\" % (fstype, dev))\n    elif fs and not force:\n        module.fail_json(msg=\"'%s' is already used as %s, use force=yes to overwrite\"%(dev,fs), rc=rc, err=err)\n\n    ### create fs\n\n    if module.check_mode:\n        changed = True\n    else:\n        mkfs = module.get_bin_path(mkfscmd, required=True)\n        cmd = None\n\n        if opts is None:\n            cmd = \"%s %s '%s'\" % (mkfs, force_flag, dev)\n        else:\n            cmd = \"%s %s %s '%s'\" % (mkfs, force_flag, opts, dev)\n        rc,_,err = module.run_command(cmd)\n        if rc == 0:\n            changed = True\n        else:\n            module.fail_json(msg=\"Creating filesystem %s on device '%s' failed\"%(fstype,dev), rc=rc, err=err)\n\n    module.exit_json(changed=changed)\n\n# import module snippets\nfrom ansible.module_utils.basic import *\nif __name__ == '__main__':\n    main()\n", "path": "lib/ansible/modules/system/filesystem.py"}], "after_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# (c) 2013, Alexander Bulimov <lazywolf0@gmail.com>\n#\n# This file is part of Ansible\n#\n# Ansible is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Ansible is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Ansible. If not, see <http://www.gnu.org/licenses/>.\n\nANSIBLE_METADATA = {'status': ['preview'],\n                    'supported_by': 'community',\n                    'version': '1.0'}\n\nDOCUMENTATION = '''\n---\nauthor: \"Alexander Bulimov (@abulimov)\"\nmodule: filesystem\nshort_description: Makes file system on block device\ndescription:\n  - This module creates file system.\nversion_added: \"1.2\"\noptions:\n  fstype:\n    description:\n    - File System type to be created.\n    - reiserfs support was added in 2.2.\n    required: true\n  dev:\n    description:\n    - Target block device. Starting in 2.3 it can also take a list of devices for file systems that allow this.\n    required: true\n  force:\n    choices: [ \"yes\", \"no\" ]\n    default: \"no\"\n    description:\n    - If yes, allows to create new filesystem on devices that already has filesystem.\n    required: false\n  resizefs:\n    choices: [ \"yes\", \"no\" ]\n    default: \"no\"\n    description:\n    - If yes, if the block device and filessytem size differ, grow the filesystem into the space. Note, XFS Will only grow if mounted.\n    required: false\n    version_added: \"2.0\"\n  opts:\n    description:\n    - List of options to be passed to mkfs command.\nnotes:\n  - uses mkfs command\n'''\n\nEXAMPLES = '''\n# Create a ext2 filesystem on /dev/sdb1.\n- filesystem:\n    fstype: ext2\n    dev: /dev/sdb1\n\n# Create a ext4 filesystem on /dev/sdb1 and check disk blocks.\n- filesystem:\n    fstype: ext4\n    dev: /dev/sdb1\n    opts: -cc\n'''\n\nimport os\nfrom ansible.module_utils.basic import AnsibleModule\n\ndef _get_dev_size(dev, module):\n    \"\"\" Return size in bytes of device. Returns int \"\"\"\n    blockdev_cmd = module.get_bin_path(\"blockdev\", required=True)\n    rc, devsize_in_bytes, err = module.run_command(\"%s %s %s\" % (blockdev_cmd, \"--getsize64\", dev))\n    return int(devsize_in_bytes)\n\n\ndef _get_fs_size(fssize_cmd, dev, module):\n    \"\"\" Return size in bytes of filesystem on device. Returns int \"\"\"\n    cmd = module.get_bin_path(fssize_cmd, required=True)\n    if 'tune2fs' == fssize_cmd:\n        # Get Block count and Block size\n        rc, size, err = module.run_command(\"%s %s %s\" % (cmd, '-l', dev))\n        if rc == 0:\n            for line in size.splitlines():\n                if 'Block count:' in line:\n                    block_count = int(line.split(':')[1].strip())\n                elif 'Block size:' in line:\n                    block_size = int(line.split(':')[1].strip())\n                    break\n        else:\n            module.fail_json(msg=\"Failed to get block count and block size of %s with %s\" % (dev, cmd), rc=rc, err=err )\n    elif 'xfs_info' == fssize_cmd:\n        # Get Block count and Block size\n        rc, size, err = module.run_command(\"%s %s\" % (cmd, dev))\n        if rc == 0:\n            for line in size.splitlines():\n                #if 'data' in line:\n                if 'data ' in line:\n                    block_size = int(line.split('=')[2].split()[0])\n                    block_count = int(line.split('=')[3].split(',')[0])\n                    break\n        else:\n            module.fail_json(msg=\"Failed to get block count and block size of %s with %s\" % (dev, cmd), rc=rc, err=err )\n    elif 'btrfs' == fssize_cmd:\n        #ToDo\n        # There is no way to get the blocksize and blockcount for btrfs filesystems\n        block_size = 1\n        block_count = 1\n\n\n    return block_size*block_count\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec = dict(\n            fstype=dict(required=True, aliases=['type']),\n            dev=dict(required=True, aliases=['device'], type='list'),\n            opts=dict(),\n            force=dict(type='bool', default='no'),\n            resizefs=dict(type='bool', default='no'),\n        ),\n        supports_check_mode=True,\n    )\n\n    # There is no \"single command\" to manipulate filesystems, so we map them all out and their options\n    fs_cmd_map = {\n        'ext2' : {\n            'mkfs' : 'mkfs.ext2',\n            'grow' : 'resize2fs',\n            'grow_flag' : None,\n            'force_flag' : '-F',\n            'fsinfo': 'tune2fs',\n        },\n        'ext3' : {\n            'mkfs' : 'mkfs.ext3',\n            'grow' : 'resize2fs',\n            'grow_flag' : None,\n            'force_flag' : '-F',\n            'fsinfo': 'tune2fs',\n        },\n        'ext4' : {\n            'mkfs' : 'mkfs.ext4',\n            'grow' : 'resize2fs',\n            'grow_flag' : None,\n            'force_flag' : '-F',\n            'fsinfo': 'tune2fs',\n        },\n        'reiserfs' : {\n            'mkfs' : 'mkfs.reiserfs',\n            'grow' : 'resize_reiserfs',\n            'grow_flag' : None,\n            'force_flag' : '-f',\n            'fsinfo': 'reiserfstune',\n        },\n        'ext4dev' : {\n            'mkfs' : 'mkfs.ext4',\n            'grow' : 'resize2fs',\n            'grow_flag' : None,\n            'force_flag' : '-F',\n            'fsinfo': 'tune2fs',\n        },\n        'xfs' : {\n            'mkfs' : 'mkfs.xfs',\n            'grow' : 'xfs_growfs',\n            'grow_flag' : None,\n            'force_flag' : '-f',\n            'fsinfo': 'xfs_info',\n        },\n        'btrfs' : {\n            'mkfs' : 'mkfs.btrfs',\n            'grow' : 'btrfs',\n            'grow_flag' : 'filesystem resize',\n            'force_flag' : '-f',\n            'fsinfo': 'btrfs',\n        }\n    }\n\n    dev = module.params['dev']\n    fstype = module.params['fstype']\n    opts = module.params['opts']\n    force = module.boolean(module.params['force'])\n    resizefs = module.boolean(module.params['resizefs'])\n\n    changed = False\n\n    try:\n        _ = fs_cmd_map[fstype]\n    except KeyError:\n        module.exit_json(changed=False, msg=\"WARNING: module does not support this filesystem yet. %s\" % fstype)\n\n    mkfscmd = fs_cmd_map[fstype]['mkfs']\n    force_flag = fs_cmd_map[fstype]['force_flag']\n    growcmd = fs_cmd_map[fstype]['grow']\n    fssize_cmd = fs_cmd_map[fstype]['fsinfo']\n\n    for device in dev:\n        if not os.path.exists(device):\n            module.fail_json(msg=\"Device %s not found.\" % device)\n\n    cmd = module.get_bin_path('blkid', required=True)\n\n    rc,raw_fs,err = module.run_command(\"%s -c /dev/null -o value -s TYPE %s\" % (cmd, ' '.join(dev)))\n    fs = raw_fs.strip()\n\n    if fs == fstype and resizefs == False and not force:\n        module.exit_json(changed=False)\n    elif fs == fstype and resizefs == True:\n        # Get dev and fs size and compare\n        devsize_in_bytes = _get_dev_size(dev, module)\n        fssize_in_bytes = _get_fs_size(fssize_cmd, dev, module)\n        if fssize_in_bytes < devsize_in_bytes:\n            fs_smaller = True\n        else:\n            fs_smaller = False\n\n\n        if module.check_mode and fs_smaller:\n            module.exit_json(changed=True, msg=\"Resizing filesystem %s on device %s\" % (fstype,dev))\n        elif module.check_mode and not fs_smaller:\n            module.exit_json(changed=False, msg=\"%s filesystem is using the whole device %s\" % (fstype, dev))\n        elif fs_smaller:\n            cmd = module.get_bin_path(growcmd, required=True)\n            rc,out,err = module.run_command(\"%s %s\" % (cmd, dev))\n            # Sadly there is no easy way to determine if this has changed. For now, just say \"true\" and move on.\n            #  in the future, you would have to parse the output to determine this.\n            #  thankfully, these are safe operations if no change is made.\n            if rc == 0:\n                module.exit_json(changed=True, msg=out)\n            else:\n                module.fail_json(msg=\"Resizing filesystem %s on device '%s' failed\"%(fstype,dev), rc=rc, err=err)\n        else:\n            module.exit_json(changed=False, msg=\"%s filesystem is using the whole device %s\" % (fstype, dev))\n    elif fs and not force:\n        module.fail_json(msg=\"'%s' is already used as %s, use force=yes to overwrite\"%(dev,fs), rc=rc, err=err)\n\n    ### create fs\n\n    if module.check_mode:\n        changed = True\n    else:\n        mkfs = module.get_bin_path(mkfscmd, required=True)\n        cmd = None\n\n        if opts is None:\n            cmd = \"%s %s '%s'\" % (mkfs, force_flag, dev)\n        else:\n            cmd = \"%s %s %s '%s'\" % (mkfs, force_flag, opts, dev)\n        rc,_,err = module.run_command(cmd)\n        if rc == 0:\n            changed = True\n        else:\n            module.fail_json(msg=\"Creating filesystem %s on device '%s' failed\"%(fstype,dev), rc=rc, err=err)\n\n    module.exit_json(changed=changed)\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/ansible/modules/system/filesystem.py"}]}