mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
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.
This commit is contained in:
parent
67c217398c
commit
f30a08d049
5 changed files with 83 additions and 37 deletions
|
@ -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:
|
||||
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 self.module.check_mode:
|
||||
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:
|
||||
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
|
||||
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…
Reference in a new issue