Add vfat support for the filesystem module (#23527)

* Add fat filesystem support

fatresize is temporarily disabled

* Refactor Filesystem.get_dev_size

For more sharing with vFAT class

* Fix filesystem tests on some OSs

I think this is due to older mke2fs on those systems.

* Fix vFAT command on FreeBSD

newfs doesn't seem to work on image files

* Refactor filesystem.grow()

Split out grow_cmd generation and Device operations

* Use swap as unsupported filesystem

Except FreeBSD, which doesn't have mkswap

* Be consistent about str(dev) vs dev.path

Prefer str(dev), this works transparently with '%s' formatting.

* Enable vfat resize, only test fatresize >= 1.0.4

Lower versions have a segfault bug.

* Only install fatresize where available

FreeBSD, OpenSUSE, RHEL and CentOS < 7 don't ship it.
pull/35773/head
Kai 7 years ago committed by Michael Scherer
parent 67c217398c
commit f30a08d049

@ -22,12 +22,13 @@ description:
version_added: "1.2"
options:
fstype:
choices: [ btrfs, ext2, ext3, ext4, ext4dev, lvm, reiserfs, xfs ]
choices: [ btrfs, ext2, ext3, ext4, ext4dev, lvm, reiserfs, xfs, vfat ]
description:
- Filesystem type to be created.
- reiserfs support was added in 2.2.
- lvm support was added in 2.5.
- since 2.5, I(dev) can be an image file.
- vfat support was added in 2.5
required: yes
dev:
description:
@ -41,8 +42,9 @@ options:
resizefs:
description:
- If C(yes), if the block device and filesytem size differ, grow the filesystem into the space.
- Supported for C(ext2), C(ext3), C(ext4), C(ext4dev), C(lvm) and C(xfs) filesystems.
- Supported for C(ext2), C(ext3), C(ext4), C(ext4dev), C(lvm), C(xfs) and C(vfat) filesystems.
- XFS Will only grow if mounted.
- vFAT will likely fail if fatresize < 1.04.
type: bool
default: 'no'
version_added: "2.0"
@ -74,8 +76,28 @@ import os
import re
import stat
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import viewkeys
from ansible.module_utils.basic import AnsibleModule, get_platform
class Device(object):
def __init__(self, module, path):
self.module = module
self.path = path
def size(self):
""" Return size in bytes of device. Returns int """
statinfo = os.stat(self.path)
if stat.S_ISBLK(statinfo.st_mode):
blockdev_cmd = self.module.get_bin_path("blockdev", required=True)
_, devsize_in_bytes, _ = self.module.run_command([blockdev_cmd, "--getsize64", self.path], check_rc=True)
return int(devsize_in_bytes)
elif os.path.isfile(self.path):
return os.path.getsize(self.path)
else:
self.module.fail_json(changed=False, msg="Target device not supported: %s" % self)
def __str__(self):
return self.path
class Filesystem(object):
@ -91,12 +113,6 @@ class Filesystem(object):
def fstype(self):
return type(self).__name__
def get_dev_size(self, dev):
""" Return size in bytes of device. Returns int """
blockdev_cmd = self.module.get_bin_path("blockdev", required=True)
_, devsize_in_bytes, _ = self.module.run_command("%s %s %s" % (blockdev_cmd, "--getsize64", dev), check_rc=True)
return int(devsize_in_bytes)
def get_fs_size(self, dev):
""" Return size in bytes of filesystem on device. Returns int """
raise NotImplementedError()
@ -112,32 +128,26 @@ class Filesystem(object):
cmd = "%s %s %s '%s'" % (mkfs, self.MKFS_FORCE_FLAGS, opts, dev)
self.module.run_command(cmd, check_rc=True)
def grow_cmd(self, dev):
cmd = self.module.get_bin_path(self.GROW, required=True)
return [cmd, str(dev)]
def grow(self, dev):
"""Get dev and fs size and compare. Returns stdout of used command."""
statinfo = os.stat(dev)
if stat.S_ISBLK(statinfo.st_mode):
devsize_in_bytes = self.get_dev_size(dev)
elif os.path.isfile(dev):
devsize_in_bytes = os.path.getsize(dev)
else:
self.module.fail_json(changed=False, msg="Target device not supported: %r." % dev)
devsize_in_bytes = dev.size()
try:
fssize_in_bytes = self.get_fs_size(dev)
except NotImplementedError:
self.module.fail_json(changed=False, msg="module does not support resizing %s filesystem yet." % self.fstype)
fs_smaller = fssize_in_bytes < devsize_in_bytes
if self.module.check_mode and fs_smaller:
self.module.exit_json(changed=True, msg="Resizing filesystem %s on device %s" % (self.fstype, dev))
elif self.module.check_mode and not fs_smaller:
if not fssize_in_bytes < devsize_in_bytes:
self.module.exit_json(changed=False, msg="%s filesystem is using the whole device %s" % (self.fstype, dev))
elif fs_smaller:
cmd = self.module.get_bin_path(self.GROW, required=True)
_, out, _ = self.module.run_command("%s %s" % (cmd, dev), check_rc=True)
return out
elif self.module.check_mode:
self.module.exit_json(changed=True, msg="Resizing filesystem %s on device %s" % (self.fstype, dev))
else:
self.module.exit_json(changed=False, msg="%s filesystem is using the whole device %s" % (self.fstype, dev))
_, out, _ = self.module.run_command(self.grow_cmd(dev), check_rc=True)
return out
class Ext(Filesystem):
@ -147,7 +157,7 @@ class Ext(Filesystem):
def get_fs_size(self, dev):
cmd = self.module.get_bin_path('tune2fs', required=True)
# Get Block count and Block size
_, size, _ = self.module.run_command([cmd, '-l', dev], check_rc=True)
_, size, _ = self.module.run_command([cmd, '-l', str(dev)], check_rc=True)
for line in size.splitlines():
if 'Block count:' in line:
block_count = int(line.split(':')[1].strip())
@ -175,7 +185,7 @@ class XFS(Filesystem):
def get_fs_size(self, dev):
cmd = self.module.get_bin_path('xfs_growfs', required=True)
_, size, _ = self.module.run_command([cmd, '-n', dev], check_rc=True)
_, size, _ = self.module.run_command([cmd, '-n', str(dev)], check_rc=True)
for line in size.splitlines():
col = line.split('=')
if col[0].strip() == 'data':
@ -215,6 +225,27 @@ class Btrfs(Filesystem):
self.module.warn('Unable to identify mkfs.btrfs version (%r, %r)' % (stdout, stderr))
class VFAT(Filesystem):
if get_platform() == 'FreeBSD':
MKFS = "newfs_msdos"
else:
MKFS = 'mkfs.vfat'
GROW = 'fatresize'
def get_fs_size(self, dev):
cmd = self.module.get_bin_path(self.GROW, required=True)
_, output, _ = self.module.run_command([cmd, '--info', str(dev)], check_rc=True)
for line in output.splitlines()[1:]:
param, value = line.split(':', 1)
if param.strip() == 'Size':
return int(value.strip())
self.module.fail_json(msg="fatresize failed to provide filesystem size for %s" % dev)
def grow_cmd(self, dev):
cmd = self.module.get_bin_path(self.GROW)
return [cmd, "-s", str(dev.size()), str(dev.path)]
class LVM(Filesystem):
MKFS = 'pvcreate'
MKFS_FORCE_FLAGS = '-f'
@ -222,7 +253,7 @@ class LVM(Filesystem):
def get_fs_size(self, dev):
cmd = self.module.get_bin_path('pvs', required=True)
_, size, _ = self.module.run_command([cmd, '--noheadings', '-o', 'pv_size', '--units', 'b', dev], check_rc=True)
_, size, _ = self.module.run_command([cmd, '--noheadings', '-o', 'pv_size', '--units', 'b', str(dev)], check_rc=True)
block_count = int(size[:-1]) # block size is 1
return block_count
@ -235,6 +266,7 @@ FILESYSTEMS = {
'reiserfs': Reiserfs,
'xfs': XFS,
'btrfs': Btrfs,
'vfat': VFAT,
'LVM2_member': LVM,
}
@ -275,6 +307,7 @@ def main():
if not os.path.exists(dev):
module.fail_json(msg="Device %s not found." % dev)
dev = Device(module, dev)
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))

@ -11,4 +11,5 @@ tested_filesystems:
ext2: {fssize: 10, grow: True}
xfs: {fssize: 20, grow: False} # grow requires a mounted filesystem
btrfs: {fssize: 100, grow: False} # grow not implemented
vfat: {fssize: 20, grow: True}
# untested: lvm, requires a block device

@ -50,7 +50,7 @@
- name: increase fake device
shell: 'dd if=/dev/zero bs=1M count=20 >> {{ dev }}'
- when: 'grow|bool'
- when: 'grow|bool and (fstype != "vfat" or resize_vfat)'
block:
- name: Expand filesystem
filesystem:
@ -81,6 +81,7 @@
- 'fs5_result is successful'
- import_tasks: overwrite_another_fs.yml
when: ansible_system != 'FreeBSD'
always:
- file:

@ -1,13 +1,8 @@
- name: 'Recreate "disk" file'
command: 'dd if=/dev/zero of={{ dev }} bs=1M count={{ fssize }}'
- name: 'Create a vfat filesystem'
command: 'mkfs.vfat {{ dev }}'
when: ansible_system != 'FreeBSD'
- name: 'Create a vfat filesystem'
command: 'newfs_msdos -F12 {{ dev }}'
when: ansible_system == 'FreeBSD'
- name: 'Create a swap filesystem'
command: 'mkswap {{ dev }}'
- command: 'blkid -c /dev/null -o value -s UUID {{ dev }}'
register: uuid

@ -31,6 +31,20 @@
- btrfsprogs
when: ansible_system == 'Linux'
- block:
- name: install fatresize
package:
name: fatresize
state: present
- command: fatresize --help
register: fatresize
- set_fact:
fatresize_version: '{{ fatresize.stdout_lines[0] | regex_search("[0-9]+\.[0-9]+\.[0-9]+") }}'
when:
- ansible_system == 'Linux'
- ansible_os_family != 'Suse'
- ansible_os_family != 'RedHat' or (ansible_distribution == 'CentOS' and ansible_distribution_version is version('7.0', '>='))
- command: mke2fs -V
register: mke2fs
@ -43,3 +57,5 @@
# Mke2fs no longer complains if the user tries to create a file system
# using the entire block device.
force_creation: "{{ e2fsprogs_version is version('1.43', '<') }}"
# Earlier versions have a segfault bug
resize_vfat: "{{ fatresize_version|default('0.0') is version('1.0.4', '>=') }}"

Loading…
Cancel
Save