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"
|
version_added: "1.2"
|
||||||
options:
|
options:
|
||||||
fstype:
|
fstype:
|
||||||
choices: [ btrfs, ext2, ext3, ext4, ext4dev, lvm, reiserfs, xfs ]
|
choices: [ btrfs, ext2, ext3, ext4, ext4dev, lvm, reiserfs, xfs, vfat ]
|
||||||
description:
|
description:
|
||||||
- Filesystem type to be created.
|
- Filesystem type to be created.
|
||||||
- reiserfs support was added in 2.2.
|
- reiserfs support was added in 2.2.
|
||||||
- lvm support was added in 2.5.
|
- lvm support was added in 2.5.
|
||||||
- since 2.5, I(dev) can be an image file.
|
- since 2.5, I(dev) can be an image file.
|
||||||
|
- vfat support was added in 2.5
|
||||||
required: yes
|
required: yes
|
||||||
dev:
|
dev:
|
||||||
description:
|
description:
|
||||||
|
@ -41,8 +42,9 @@ options:
|
||||||
resizefs:
|
resizefs:
|
||||||
description:
|
description:
|
||||||
- If C(yes), if the block device and filesytem size differ, grow the filesystem into the space.
|
- 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.
|
- XFS Will only grow if mounted.
|
||||||
|
- vFAT will likely fail if fatresize < 1.04.
|
||||||
type: bool
|
type: bool
|
||||||
default: 'no'
|
default: 'no'
|
||||||
version_added: "2.0"
|
version_added: "2.0"
|
||||||
|
@ -74,8 +76,28 @@ import os
|
||||||
import re
|
import re
|
||||||
import stat
|
import stat
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule, get_platform
|
||||||
from ansible.module_utils.six import viewkeys
|
|
||||||
|
|
||||||
|
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):
|
class Filesystem(object):
|
||||||
|
@ -91,12 +113,6 @@ class Filesystem(object):
|
||||||
def fstype(self):
|
def fstype(self):
|
||||||
return type(self).__name__
|
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):
|
def get_fs_size(self, dev):
|
||||||
""" Return size in bytes of filesystem on device. Returns int """
|
""" Return size in bytes of filesystem on device. Returns int """
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -112,32 +128,26 @@ class Filesystem(object):
|
||||||
cmd = "%s %s %s '%s'" % (mkfs, self.MKFS_FORCE_FLAGS, opts, dev)
|
cmd = "%s %s %s '%s'" % (mkfs, self.MKFS_FORCE_FLAGS, opts, dev)
|
||||||
self.module.run_command(cmd, check_rc=True)
|
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):
|
def grow(self, dev):
|
||||||
"""Get dev and fs size and compare. Returns stdout of used command."""
|
"""Get dev and fs size and compare. Returns stdout of used command."""
|
||||||
statinfo = os.stat(dev)
|
devsize_in_bytes = dev.size()
|
||||||
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)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fssize_in_bytes = self.get_fs_size(dev)
|
fssize_in_bytes = self.get_fs_size(dev)
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
self.module.fail_json(changed=False, msg="module does not support resizing %s filesystem yet." % self.fstype)
|
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))
|
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:
|
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):
|
class Ext(Filesystem):
|
||||||
|
@ -147,7 +157,7 @@ class Ext(Filesystem):
|
||||||
def get_fs_size(self, dev):
|
def get_fs_size(self, dev):
|
||||||
cmd = self.module.get_bin_path('tune2fs', required=True)
|
cmd = self.module.get_bin_path('tune2fs', required=True)
|
||||||
# Get Block count and Block size
|
# 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():
|
for line in size.splitlines():
|
||||||
if 'Block count:' in line:
|
if 'Block count:' in line:
|
||||||
block_count = int(line.split(':')[1].strip())
|
block_count = int(line.split(':')[1].strip())
|
||||||
|
@ -175,7 +185,7 @@ class XFS(Filesystem):
|
||||||
|
|
||||||
def get_fs_size(self, dev):
|
def get_fs_size(self, dev):
|
||||||
cmd = self.module.get_bin_path('xfs_growfs', required=True)
|
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():
|
for line in size.splitlines():
|
||||||
col = line.split('=')
|
col = line.split('=')
|
||||||
if col[0].strip() == 'data':
|
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))
|
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):
|
class LVM(Filesystem):
|
||||||
MKFS = 'pvcreate'
|
MKFS = 'pvcreate'
|
||||||
MKFS_FORCE_FLAGS = '-f'
|
MKFS_FORCE_FLAGS = '-f'
|
||||||
|
@ -222,7 +253,7 @@ class LVM(Filesystem):
|
||||||
|
|
||||||
def get_fs_size(self, dev):
|
def get_fs_size(self, dev):
|
||||||
cmd = self.module.get_bin_path('pvs', required=True)
|
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
|
block_count = int(size[:-1]) # block size is 1
|
||||||
return block_count
|
return block_count
|
||||||
|
|
||||||
|
@ -235,6 +266,7 @@ FILESYSTEMS = {
|
||||||
'reiserfs': Reiserfs,
|
'reiserfs': Reiserfs,
|
||||||
'xfs': XFS,
|
'xfs': XFS,
|
||||||
'btrfs': Btrfs,
|
'btrfs': Btrfs,
|
||||||
|
'vfat': VFAT,
|
||||||
'LVM2_member': LVM,
|
'LVM2_member': LVM,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,6 +307,7 @@ def main():
|
||||||
|
|
||||||
if not os.path.exists(dev):
|
if not os.path.exists(dev):
|
||||||
module.fail_json(msg="Device %s not found." % dev)
|
module.fail_json(msg="Device %s not found." % dev)
|
||||||
|
dev = Device(module, dev)
|
||||||
|
|
||||||
cmd = module.get_bin_path('blkid', required=True)
|
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, dev))
|
||||||
|
|
|
@ -11,4 +11,5 @@ tested_filesystems:
|
||||||
ext2: {fssize: 10, grow: True}
|
ext2: {fssize: 10, grow: True}
|
||||||
xfs: {fssize: 20, grow: False} # grow requires a mounted filesystem
|
xfs: {fssize: 20, grow: False} # grow requires a mounted filesystem
|
||||||
btrfs: {fssize: 100, grow: False} # grow not implemented
|
btrfs: {fssize: 100, grow: False} # grow not implemented
|
||||||
|
vfat: {fssize: 20, grow: True}
|
||||||
# untested: lvm, requires a block device
|
# untested: lvm, requires a block device
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
- name: increase fake device
|
- name: increase fake device
|
||||||
shell: 'dd if=/dev/zero bs=1M count=20 >> {{ dev }}'
|
shell: 'dd if=/dev/zero bs=1M count=20 >> {{ dev }}'
|
||||||
|
|
||||||
- when: 'grow|bool'
|
- when: 'grow|bool and (fstype != "vfat" or resize_vfat)'
|
||||||
block:
|
block:
|
||||||
- name: Expand filesystem
|
- name: Expand filesystem
|
||||||
filesystem:
|
filesystem:
|
||||||
|
@ -81,6 +81,7 @@
|
||||||
- 'fs5_result is successful'
|
- 'fs5_result is successful'
|
||||||
|
|
||||||
- import_tasks: overwrite_another_fs.yml
|
- import_tasks: overwrite_another_fs.yml
|
||||||
|
when: ansible_system != 'FreeBSD'
|
||||||
|
|
||||||
always:
|
always:
|
||||||
- file:
|
- file:
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
- name: 'Recreate "disk" file'
|
- name: 'Recreate "disk" file'
|
||||||
command: 'dd if=/dev/zero of={{ dev }} bs=1M count={{ fssize }}'
|
command: 'dd if=/dev/zero of={{ dev }} bs=1M count={{ fssize }}'
|
||||||
|
|
||||||
- name: 'Create a vfat filesystem'
|
- name: 'Create a swap filesystem'
|
||||||
command: 'mkfs.vfat {{ dev }}'
|
command: 'mkswap {{ dev }}'
|
||||||
when: ansible_system != 'FreeBSD'
|
|
||||||
|
|
||||||
- name: 'Create a vfat filesystem'
|
|
||||||
command: 'newfs_msdos -F12 {{ dev }}'
|
|
||||||
when: ansible_system == 'FreeBSD'
|
|
||||||
|
|
||||||
- command: 'blkid -c /dev/null -o value -s UUID {{ dev }}'
|
- command: 'blkid -c /dev/null -o value -s UUID {{ dev }}'
|
||||||
register: uuid
|
register: uuid
|
||||||
|
|
|
@ -31,6 +31,20 @@
|
||||||
- btrfsprogs
|
- btrfsprogs
|
||||||
when: ansible_system == 'Linux'
|
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
|
- command: mke2fs -V
|
||||||
register: mke2fs
|
register: mke2fs
|
||||||
|
|
||||||
|
@ -43,3 +57,5 @@
|
||||||
# Mke2fs no longer complains if the user tries to create a file system
|
# Mke2fs no longer complains if the user tries to create a file system
|
||||||
# using the entire block device.
|
# using the entire block device.
|
||||||
force_creation: "{{ e2fsprogs_version is version('1.43', '<') }}"
|
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