mirror of
https://github.com/ansible-collections/ansible.posix.git
synced 2026-01-11 15:15:26 +01:00
Add ephemeral state to mount fs without altering fstab
This commit is contained in:
parent
55bd196e82
commit
04089e80fb
3 changed files with 416 additions and 22 deletions
4
changelogs/fragments/267_mount_ephemeral.yml
Normal file
4
changelogs/fragments/267_mount_ephemeral.yml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
minor_changes:
|
||||||
|
- mount - Add ``ephemeral`` value for the ``state`` parameter, that allows to mount a filesystem
|
||||||
|
without altering the ``fstab`` file (https://github.com/ansible-collections/ansible.posix/pull/267).
|
||||||
|
|
@ -31,12 +31,12 @@ options:
|
||||||
src:
|
src:
|
||||||
description:
|
description:
|
||||||
- Device (or NFS volume, or something else) to be mounted on I(path).
|
- Device (or NFS volume, or something else) to be mounted on I(path).
|
||||||
- Required when I(state) set to C(present) or C(mounted).
|
- Required when I(state) set to C(present), C(mounted) or C(ephemeral).
|
||||||
type: path
|
type: path
|
||||||
fstype:
|
fstype:
|
||||||
description:
|
description:
|
||||||
- Filesystem type.
|
- Filesystem type.
|
||||||
- Required when I(state) is C(present) or C(mounted).
|
- Required when I(state) is C(present), C(mounted) or C(ephemeral).
|
||||||
type: str
|
type: str
|
||||||
opts:
|
opts:
|
||||||
description:
|
description:
|
||||||
|
|
@ -48,7 +48,7 @@ options:
|
||||||
- Note that if set to C(null) and I(state) set to C(present),
|
- Note that if set to C(null) and I(state) set to C(present),
|
||||||
it will cease to work and duplicate entries will be made
|
it will cease to work and duplicate entries will be made
|
||||||
with subsequent runs.
|
with subsequent runs.
|
||||||
- Has no effect on Solaris systems.
|
- Has no effect on Solaris systems or when used with C(ephemeral).
|
||||||
type: str
|
type: str
|
||||||
default: '0'
|
default: '0'
|
||||||
passno:
|
passno:
|
||||||
|
|
@ -57,7 +57,7 @@ options:
|
||||||
- Note that if set to C(null) and I(state) set to C(present),
|
- Note that if set to C(null) and I(state) set to C(present),
|
||||||
it will cease to work and duplicate entries will be made
|
it will cease to work and duplicate entries will be made
|
||||||
with subsequent runs.
|
with subsequent runs.
|
||||||
- Deprecated on Solaris systems.
|
- Deprecated on Solaris systems. Has no effect when used with C(ephemeral).
|
||||||
type: str
|
type: str
|
||||||
default: '0'
|
default: '0'
|
||||||
state:
|
state:
|
||||||
|
|
@ -68,6 +68,13 @@ options:
|
||||||
- If C(unmounted), the device will be unmounted without changing I(fstab).
|
- If C(unmounted), the device will be unmounted without changing I(fstab).
|
||||||
- C(present) only specifies that the device is to be configured in
|
- C(present) only specifies that the device is to be configured in
|
||||||
I(fstab) and does not trigger or require a mount.
|
I(fstab) and does not trigger or require a mount.
|
||||||
|
- C(ephemeral) only specifies that the device is to be mounted, without changing
|
||||||
|
I(fstab). If it is already mounted, a remount will be triggered.
|
||||||
|
This will always return changed=True. If the mount point I(path)
|
||||||
|
has already a device mounted on, and its source is different than I(src),
|
||||||
|
the module will fail to avoid unexpected unmount or mount point override.
|
||||||
|
If the mount point is not present, the mount point will be created.
|
||||||
|
The I(fstab) is completely ignored.
|
||||||
- C(absent) specifies that the device mount's entry will be removed from
|
- C(absent) specifies that the device mount's entry will be removed from
|
||||||
I(fstab) and will also unmount the device and remove the mount
|
I(fstab) and will also unmount the device and remove the mount
|
||||||
point.
|
point.
|
||||||
|
|
@ -77,10 +84,12 @@ options:
|
||||||
applied to the remount, but will not change I(fstab). Additionally,
|
applied to the remount, but will not change I(fstab). Additionally,
|
||||||
if I(opts) is set, and the remount command fails, the module will
|
if I(opts) is set, and the remount command fails, the module will
|
||||||
error to prevent unexpected mount changes. Try using C(mounted)
|
error to prevent unexpected mount changes. Try using C(mounted)
|
||||||
instead to work around this issue.
|
instead to work around this issue. C(remounted) expects the mount point
|
||||||
|
to be present in the I(fstab). To remount a mount point not registered
|
||||||
|
in I(fstab), use C(ephemeral) instead, especially with BSD nodes.
|
||||||
type: str
|
type: str
|
||||||
required: true
|
required: true
|
||||||
choices: [ absent, mounted, present, unmounted, remounted ]
|
choices: [ absent, mounted, present, unmounted, remounted, ephemeral ]
|
||||||
fstab:
|
fstab:
|
||||||
description:
|
description:
|
||||||
- File to use instead of C(/etc/fstab).
|
- File to use instead of C(/etc/fstab).
|
||||||
|
|
@ -89,6 +98,7 @@ options:
|
||||||
- OpenBSD does not allow specifying alternate fstab files with mount so do not
|
- OpenBSD does not allow specifying alternate fstab files with mount so do not
|
||||||
use this on OpenBSD with any state that operates on the live filesystem.
|
use this on OpenBSD with any state that operates on the live filesystem.
|
||||||
- This parameter defaults to /etc/fstab or /etc/vfstab on Solaris.
|
- This parameter defaults to /etc/fstab or /etc/vfstab on Solaris.
|
||||||
|
- This parameter is ignored when I(state) is set to C(ephemeral).
|
||||||
type: str
|
type: str
|
||||||
boot:
|
boot:
|
||||||
description:
|
description:
|
||||||
|
|
@ -100,6 +110,7 @@ options:
|
||||||
to mount options in I(/etc/fstab).
|
to mount options in I(/etc/fstab).
|
||||||
- To avoid mount option conflicts, if C(noauto) specified in C(opts),
|
- To avoid mount option conflicts, if C(noauto) specified in C(opts),
|
||||||
mount module will ignore C(boot).
|
mount module will ignore C(boot).
|
||||||
|
- This parameter is ignored when I(state) is set to C(ephemeral).
|
||||||
type: bool
|
type: bool
|
||||||
default: yes
|
default: yes
|
||||||
backup:
|
backup:
|
||||||
|
|
@ -184,6 +195,14 @@ EXAMPLES = r'''
|
||||||
boot: no
|
boot: no
|
||||||
state: mounted
|
state: mounted
|
||||||
fstype: nfs
|
fstype: nfs
|
||||||
|
|
||||||
|
- name: Mount ephemeral SMB volume
|
||||||
|
ansible.posix.mount:
|
||||||
|
src: //192.168.1.200/share
|
||||||
|
path: /mnt/smb_share
|
||||||
|
opts: "rw,vers=3,file_mode=0600,dir_mode=0700,dom={{ ad_domain }},username={{ ad_username }},password={{ ad_password }}"
|
||||||
|
fstype: cifs
|
||||||
|
state: ephemeral
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
|
|
@ -430,6 +449,24 @@ def _set_fstab_args(fstab_file):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _set_ephemeral_args(args):
|
||||||
|
result = []
|
||||||
|
# Set fstype switch according to platform. SunOS/Solaris use -F
|
||||||
|
if platform.system().lower() == 'sunos':
|
||||||
|
result.append('-F')
|
||||||
|
else:
|
||||||
|
result.append('-t')
|
||||||
|
result.append(args['fstype'])
|
||||||
|
|
||||||
|
# Even if '-o remount' is already set, specifying multiple -o is valid
|
||||||
|
if args['opts'] != 'defaults':
|
||||||
|
result += ['-o', args['opts']]
|
||||||
|
|
||||||
|
result.append(args['src'])
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def mount(module, args):
|
def mount(module, args):
|
||||||
"""Mount up a path or remount if needed."""
|
"""Mount up a path or remount if needed."""
|
||||||
|
|
||||||
|
|
@ -446,7 +483,11 @@ def mount(module, args):
|
||||||
'OpenBSD does not support alternate fstab files. Do not '
|
'OpenBSD does not support alternate fstab files. Do not '
|
||||||
'specify the fstab parameter for OpenBSD hosts'))
|
'specify the fstab parameter for OpenBSD hosts'))
|
||||||
else:
|
else:
|
||||||
cmd += _set_fstab_args(args['fstab'])
|
if module.params['state'] != 'ephemeral':
|
||||||
|
cmd += _set_fstab_args(args['fstab'])
|
||||||
|
|
||||||
|
if module.params['state'] == 'ephemeral':
|
||||||
|
cmd += _set_ephemeral_args(args)
|
||||||
|
|
||||||
cmd += [name]
|
cmd += [name]
|
||||||
|
|
||||||
|
|
@ -498,18 +539,24 @@ def remount(module, args):
|
||||||
'OpenBSD does not support alternate fstab files. Do not '
|
'OpenBSD does not support alternate fstab files. Do not '
|
||||||
'specify the fstab parameter for OpenBSD hosts'))
|
'specify the fstab parameter for OpenBSD hosts'))
|
||||||
else:
|
else:
|
||||||
cmd += _set_fstab_args(args['fstab'])
|
if module.params['state'] != 'ephemeral':
|
||||||
|
cmd += _set_fstab_args(args['fstab'])
|
||||||
|
|
||||||
|
if module.params['state'] == 'ephemeral':
|
||||||
|
cmd += _set_ephemeral_args(args)
|
||||||
|
|
||||||
cmd += [args['name']]
|
cmd += [args['name']]
|
||||||
out = err = ''
|
out = err = ''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if platform.system().lower().endswith('bsd'):
|
if module.params['state'] != 'ephemeral' and platform.system().lower().endswith('bsd'):
|
||||||
# Note: Forcing BSDs to do umount/mount due to BSD remount not
|
# Note: Forcing BSDs to do umount/mount due to BSD remount not
|
||||||
# working as expected (suspect bug in the BSD mount command)
|
# working as expected (suspect bug in the BSD mount command)
|
||||||
# Interested contributor could rework this to use mount options on
|
# Interested contributor could rework this to use mount options on
|
||||||
# the CLI instead of relying on fstab
|
# the CLI instead of relying on fstab
|
||||||
# https://github.com/ansible/ansible-modules-core/issues/5591
|
# https://github.com/ansible/ansible-modules-core/issues/5591
|
||||||
|
# Note: this does not affect ephemeral state as all options
|
||||||
|
# are set on the CLI and fstab is expected to be ignored.
|
||||||
rc = 1
|
rc = 1
|
||||||
else:
|
else:
|
||||||
rc, out, err = module.run_command(cmd)
|
rc, out, err = module.run_command(cmd)
|
||||||
|
|
@ -663,6 +710,47 @@ def get_linux_mounts(module, mntinfo_file="/proc/self/mountinfo"):
|
||||||
return mounts
|
return mounts
|
||||||
|
|
||||||
|
|
||||||
|
def _is_same_mount_src(module, src, mountpoint, linux_mounts):
|
||||||
|
"""Return True if the mounted fs on mountpoint is the same source than src. Return False if mountpoint is not a mountpoint"""
|
||||||
|
# If the provided mountpoint is not a mountpoint, don't waste time
|
||||||
|
if (
|
||||||
|
not ismount(mountpoint) and
|
||||||
|
not is_bind_mounted(module, linux_mounts, mountpoint)):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Treat Linux bind mounts
|
||||||
|
if platform.system() == 'Linux' and linux_mounts is not None:
|
||||||
|
# For Linux bind mounts only: the mount command does not return
|
||||||
|
# the actual source for bind mounts, but the device of the source.
|
||||||
|
# is_bind_mounted() called with the 'src' parameter will return True if
|
||||||
|
# the mountpoint is a bind mount AND the source FS is the same than 'src'.
|
||||||
|
# is_bind_mounted() is not reliable on Solaris, NetBSD and OpenBSD.
|
||||||
|
# But we can rely on 'mount -v' on all other platforms, and Linux non-bind mounts.
|
||||||
|
if (is_bind_mounted(module, linux_mounts, mountpoint, src)):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# mount with parameter -v has a close behavior on Linux, *BSD, SunOS
|
||||||
|
# Requires -v with SunOS. Without -v, source and destination are reversed
|
||||||
|
# Output format differs from a system to another, but field[0:3] are consistent: [src, 'on', dest]
|
||||||
|
cmd = '%s -v' % module.get_bin_path('mount', required=True)
|
||||||
|
rc, out, err = module.run_command(cmd)
|
||||||
|
mounts = []
|
||||||
|
|
||||||
|
if len(out):
|
||||||
|
mounts = to_native(out).strip().split('\n')
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="Unable to retrieve mount info with command '%s'" % cmd)
|
||||||
|
|
||||||
|
for mnt in mounts:
|
||||||
|
fields = mnt.split()
|
||||||
|
mp_src = fields[0]
|
||||||
|
mp_dst = fields[2]
|
||||||
|
if mp_src == src and mp_dst == mountpoint:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec=dict(
|
argument_spec=dict(
|
||||||
|
|
@ -675,12 +763,13 @@ def main():
|
||||||
passno=dict(type='str', no_log=False, default='0'),
|
passno=dict(type='str', no_log=False, default='0'),
|
||||||
src=dict(type='path'),
|
src=dict(type='path'),
|
||||||
backup=dict(type='bool', default=False),
|
backup=dict(type='bool', default=False),
|
||||||
state=dict(type='str', required=True, choices=['absent', 'mounted', 'present', 'unmounted', 'remounted']),
|
state=dict(type='str', required=True, choices=['absent', 'mounted', 'present', 'unmounted', 'remounted', 'ephemeral']),
|
||||||
),
|
),
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
required_if=(
|
required_if=(
|
||||||
['state', 'mounted', ['src', 'fstype']],
|
['state', 'mounted', ['src', 'fstype']],
|
||||||
['state', 'present', ['src', 'fstype']],
|
['state', 'present', ['src', 'fstype']],
|
||||||
|
['state', 'ephemeral', ['src', 'fstype']]
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -751,15 +840,17 @@ def main():
|
||||||
|
|
||||||
# If fstab file does not exist, we first need to create it. This mainly
|
# If fstab file does not exist, we first need to create it. This mainly
|
||||||
# happens when fstab option is passed to the module.
|
# happens when fstab option is passed to the module.
|
||||||
if not os.path.exists(args['fstab']):
|
# If state is 'ephemeral', we do not need fstab file
|
||||||
if not os.path.exists(os.path.dirname(args['fstab'])):
|
if module.params['state'] != 'ephemeral':
|
||||||
os.makedirs(os.path.dirname(args['fstab']))
|
if not os.path.exists(args['fstab']):
|
||||||
try:
|
if not os.path.exists(os.path.dirname(args['fstab'])):
|
||||||
open(args['fstab'], 'a').close()
|
os.makedirs(os.path.dirname(args['fstab']))
|
||||||
except PermissionError as e:
|
try:
|
||||||
module.fail_json(msg="Failed to open %s due to permission issue" % args['fstab'])
|
open(args['fstab'], 'a').close()
|
||||||
except Exception as e:
|
except PermissionError as e:
|
||||||
module.fail_json(msg="Failed to open %s due to %s" % (args['fstab'], to_native(e)))
|
module.fail_json(msg="Failed to open %s due to permission issue" % args['fstab'])
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg="Failed to open %s due to %s" % (args['fstab'], to_native(e)))
|
||||||
|
|
||||||
# absent:
|
# absent:
|
||||||
# Remove from fstab and unmounted.
|
# Remove from fstab and unmounted.
|
||||||
|
|
@ -770,6 +861,8 @@ def main():
|
||||||
# mounted:
|
# mounted:
|
||||||
# Add to fstab if not there and make sure it is mounted. If it has
|
# Add to fstab if not there and make sure it is mounted. If it has
|
||||||
# changed in fstab then remount it.
|
# changed in fstab then remount it.
|
||||||
|
# ephemeral:
|
||||||
|
# Do not change fstab state, but mount.
|
||||||
|
|
||||||
state = module.params['state']
|
state = module.params['state']
|
||||||
name = module.params['path']
|
name = module.params['path']
|
||||||
|
|
@ -801,7 +894,7 @@ def main():
|
||||||
msg="Error unmounting %s: %s" % (name, msg))
|
msg="Error unmounting %s: %s" % (name, msg))
|
||||||
|
|
||||||
changed = True
|
changed = True
|
||||||
elif state == 'mounted':
|
elif state == 'mounted' or state == 'ephemeral':
|
||||||
dirs_created = []
|
dirs_created = []
|
||||||
if not os.path.exists(name) and not module.check_mode:
|
if not os.path.exists(name) and not module.check_mode:
|
||||||
try:
|
try:
|
||||||
|
|
@ -829,7 +922,11 @@ def main():
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Error making dir %s: %s" % (name, to_native(e)))
|
msg="Error making dir %s: %s" % (name, to_native(e)))
|
||||||
|
|
||||||
name, backup_lines, changed = _set_mount_save_old(module, args)
|
# ephemeral: completely ignore fstab
|
||||||
|
if state != 'ephemeral':
|
||||||
|
name, backup_lines, changed = _set_mount_save_old(module, args)
|
||||||
|
else:
|
||||||
|
name, backup_lines, changed = args['name'], [], False
|
||||||
res = 0
|
res = 0
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|
@ -839,7 +936,26 @@ def main():
|
||||||
if changed and not module.check_mode:
|
if changed and not module.check_mode:
|
||||||
res, msg = remount(module, args)
|
res, msg = remount(module, args)
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
|
# When 'state' == 'ephemeral', we don't know what is in fstab, and 'changed' is always False
|
||||||
|
if state == 'ephemeral':
|
||||||
|
# If state == 'ephemeral', check if the mountpoint src == module.params['src']
|
||||||
|
# If it doesn't, fail to prevent unwanted unmount or unwanted mountpoint override
|
||||||
|
if _is_same_mount_src(module, args['src'], args['name'], linux_mounts):
|
||||||
|
changed = True
|
||||||
|
if not module.check_mode:
|
||||||
|
res, msg = remount(module, args)
|
||||||
|
else:
|
||||||
|
module.fail_json(
|
||||||
|
msg=(
|
||||||
|
'Ephemeral mount point is already mounted with a different '
|
||||||
|
'source than the specified one. Failing in order to prevent an '
|
||||||
|
'unwanted unmount or override operation. Try replacing this command with '
|
||||||
|
'a "state: unmounted" followed by a "state: ephemeral", or use '
|
||||||
|
'a different destination path.'))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
# If not already mounted, mount it
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
if not module.check_mode:
|
if not module.check_mode:
|
||||||
|
|
@ -851,7 +967,8 @@ def main():
|
||||||
# A non-working fstab entry may break the system at the reboot,
|
# A non-working fstab entry may break the system at the reboot,
|
||||||
# so undo all the changes if possible.
|
# so undo all the changes if possible.
|
||||||
try:
|
try:
|
||||||
write_fstab(module, backup_lines, args['fstab'])
|
if state != 'ephemeral':
|
||||||
|
write_fstab(module, backup_lines, args['fstab'])
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
- name: Install dependencies
|
||||||
|
ansible.builtin.package:
|
||||||
|
name: e2fsprogs
|
||||||
|
state: present
|
||||||
|
when: ansible_system == 'Linux'
|
||||||
|
|
||||||
- name: Create the mount point
|
- name: Create the mount point
|
||||||
file:
|
file:
|
||||||
state: directory
|
state: directory
|
||||||
|
|
@ -406,3 +412,270 @@
|
||||||
- /tmp/myfs1
|
- /tmp/myfs1
|
||||||
- /tmp/test_fstab
|
- /tmp/test_fstab
|
||||||
when: ansible_system in ('Linux')
|
when: ansible_system in ('Linux')
|
||||||
|
|
||||||
|
- name: Block to test ephemeral option
|
||||||
|
environment:
|
||||||
|
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
|
block:
|
||||||
|
- name: Create empty file A
|
||||||
|
community.general.filesize:
|
||||||
|
path: /tmp/myfs_A.img
|
||||||
|
size: 20M
|
||||||
|
|
||||||
|
- name: Create empty file B
|
||||||
|
community.general.filesize:
|
||||||
|
path: /tmp/myfs_B.img
|
||||||
|
size: 20M
|
||||||
|
|
||||||
|
- name: Register facts on Linux
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
ephemeral_device_A: /tmp/myfs_A.img
|
||||||
|
ephemeral_device_B: /tmp/myfs_B.img
|
||||||
|
ephemeral_fstype: ext3
|
||||||
|
ephemeral_fstab: /etc/fstab
|
||||||
|
when: ansible_system == 'Linux'
|
||||||
|
|
||||||
|
- name: Register facts on Solaris/SunOS
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
ephemeral_device_A: /dev/lofi/1
|
||||||
|
ephemeral_device_B: /dev/lofi/2
|
||||||
|
ephemeral_create_loop_dev_cmd: >
|
||||||
|
lofiadm -a /tmp/myfs_A.img /dev/lofi/1 &&
|
||||||
|
lofiadm -a /tmp/myfs_B.img /dev/lofi/2
|
||||||
|
ephemeral_remove_loop_dev_cmd: >
|
||||||
|
lofiadm -d /dev/lofi/1 &&
|
||||||
|
lofiadm -d /dev/lofi/2 || true
|
||||||
|
ephemeral_fstype: ufs
|
||||||
|
ephemeral_fstab: /etc/vfstab
|
||||||
|
when: ansible_system == 'SunOS'
|
||||||
|
|
||||||
|
- name: Register facts on FreeBSD
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
ephemeral_device_A: /dev/md1
|
||||||
|
ephemeral_device_B: /dev/md2
|
||||||
|
ephemeral_create_loop_dev_cmd: >
|
||||||
|
mdconfig -a -t vnode -f /tmp/myfs_A.img -u /dev/md1 &&
|
||||||
|
mdconfig -a -t vnode -f /tmp/myfs_B.img -u /dev/md2
|
||||||
|
ephemeral_remove_loop_dev_cmd: >
|
||||||
|
mdconfig -d -u /dev/md1 &&
|
||||||
|
mdconfig -d -u /dev/md2
|
||||||
|
ephemeral_fstype: ufs
|
||||||
|
ephemeral_fstab: /etc/fstab
|
||||||
|
when: ansible_system == 'FreeBSD'
|
||||||
|
|
||||||
|
- name: Register facts on NetBSD
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
ephemeral_device_A: /dev/vnd1
|
||||||
|
ephemeral_device_B: /dev/vnd2
|
||||||
|
ephemeral_create_loop_dev_cmd: >
|
||||||
|
vnconfig /dev/vnd1 /tmp/myfs_A.img &&
|
||||||
|
vnconfig /dev/vnd2 /tmp/myfs_B.img
|
||||||
|
ephemeral_remove_loop_dev_cmd: >
|
||||||
|
vnconfig -u /dev/vnd1 &&
|
||||||
|
vnconfig -u /dev/vnd2
|
||||||
|
ephemeral_fstype: ufs
|
||||||
|
ephemeral_fstab: /etc/fstab
|
||||||
|
when: ansible_system == 'NetBSD'
|
||||||
|
|
||||||
|
- name: Register format fs command on Non-Linux and Non-OpenBSD
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
ephemeral_format_fs_cmd: >
|
||||||
|
yes | newfs {{ ephemeral_device_A }} &&
|
||||||
|
yes | newfs {{ ephemeral_device_B }}
|
||||||
|
when: ansible_system in ('SunOS', 'FreeBSD', 'NetBSD')
|
||||||
|
|
||||||
|
- name: Register facts on OpenBSD
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
ephemeral_device_A: /dev/vnd1c
|
||||||
|
ephemeral_device_B: /dev/vnd2c
|
||||||
|
ephemeral_create_loop_dev_cmd: >
|
||||||
|
vnconfig vnd1 /tmp/myfs_A.img &&
|
||||||
|
vnconfig vnd2 /tmp/myfs_B.img
|
||||||
|
ephemeral_remove_loop_dev_cmd: >
|
||||||
|
vnconfig -u vnd1 &&
|
||||||
|
vnconfig -u vnd2
|
||||||
|
ephemeral_format_fs_cmd: >
|
||||||
|
yes | newfs /dev/rvnd1c &&
|
||||||
|
yes | newfs /dev/rvnd2c
|
||||||
|
ephemeral_fstype: ffs
|
||||||
|
ephemeral_fstab: /etc/fstab
|
||||||
|
when: ansible_system == 'OpenBSD'
|
||||||
|
|
||||||
|
##### FORMAT FS ON LINUX
|
||||||
|
|
||||||
|
- name: Block to format FS on Linux
|
||||||
|
block:
|
||||||
|
- name: Format FS A on Linux
|
||||||
|
community.general.filesystem:
|
||||||
|
fstype: ext3
|
||||||
|
dev: /tmp/myfs_A.img
|
||||||
|
|
||||||
|
- name: Format FS B on Linux
|
||||||
|
community.general.filesystem:
|
||||||
|
fstype: ext3
|
||||||
|
dev: /tmp/myfs_B.img
|
||||||
|
when: ansible_system == 'Linux'
|
||||||
|
|
||||||
|
##### FORMAT FS ON SOLARIS AND BSD
|
||||||
|
|
||||||
|
- name: Create loop devices on Solaris and BSD
|
||||||
|
ansible.builtin.shell: "{{ ephemeral_create_loop_dev_cmd }}"
|
||||||
|
when: ephemeral_create_loop_dev_cmd is defined
|
||||||
|
|
||||||
|
- name: Format FS A and B on Solaris and BSD
|
||||||
|
ansible.builtin.shell: "{{ ephemeral_format_fs_cmd }}"
|
||||||
|
when: ephemeral_format_fs_cmd is defined
|
||||||
|
|
||||||
|
##### TESTS
|
||||||
|
|
||||||
|
- name: Create fstab if it does not exist
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ ephemeral_fstab }}"
|
||||||
|
state: touch
|
||||||
|
|
||||||
|
- name: Get checksum of /etc/fstab before mounting anything
|
||||||
|
stat:
|
||||||
|
path: '{{ ephemeral_fstab }}'
|
||||||
|
register: fstab_stat_before_mount
|
||||||
|
|
||||||
|
- name: Mount the FS A with ephemeral state
|
||||||
|
mount:
|
||||||
|
path: /tmp/myfs
|
||||||
|
src: '{{ ephemeral_device_A }}'
|
||||||
|
fstype: '{{ ephemeral_fstype }}'
|
||||||
|
opts: rw
|
||||||
|
state: ephemeral
|
||||||
|
register: ephemeral_mount_info
|
||||||
|
|
||||||
|
- name: Put something in the directory so we can do additional checks later on
|
||||||
|
copy:
|
||||||
|
content: 'Testing'
|
||||||
|
dest: /tmp/myfs/test_file
|
||||||
|
|
||||||
|
- name: Get checksum of /etc/fstab after an ephemeral mount
|
||||||
|
stat:
|
||||||
|
path: '{{ ephemeral_fstab }}'
|
||||||
|
register: fstab_stat_after_mount
|
||||||
|
|
||||||
|
- name: Get mountinfo
|
||||||
|
shell: mount -v | awk '{print $3}' | grep '^/tmp/myfs$' | wc -l
|
||||||
|
register: check_mountinfo
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- name: Assert the mount occured and the fstab is unchanged
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- check_mountinfo.stdout|int == 1
|
||||||
|
- ephemeral_mount_info['changed']
|
||||||
|
- fstab_stat_before_mount['stat']['checksum'] == fstab_stat_after_mount['stat']['checksum']
|
||||||
|
|
||||||
|
- name: Get first mount record
|
||||||
|
shell: mount -v | grep '/tmp/myfs'
|
||||||
|
register: ephemeral_mount_record_1
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- name: Try to mount FS A where FS A is already mounted (should trigger remount and changed)
|
||||||
|
mount:
|
||||||
|
path: /tmp/myfs
|
||||||
|
src: '{{ ephemeral_device_A }}'
|
||||||
|
fstype: '{{ ephemeral_fstype }}'
|
||||||
|
opts: ro
|
||||||
|
state: ephemeral
|
||||||
|
register: ephemeral_mount_info
|
||||||
|
|
||||||
|
- name: Get second mount record (should be different than the first)
|
||||||
|
shell: mount -v | grep '/tmp/myfs'
|
||||||
|
register: ephemeral_mount_record_2
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- name: Get mountinfo
|
||||||
|
shell: mount -v | awk '{print $3}' | grep '^/tmp/myfs$' | wc -l
|
||||||
|
register: check_mountinfo
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- name: Assert the FS A is still mounted, the options changed and the fstab unchanged
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- check_mountinfo.stdout|int == 1
|
||||||
|
- ephemeral_mount_record_1.stdout != ephemeral_mount_record_2.stdout
|
||||||
|
- ephemeral_mount_info['changed']
|
||||||
|
- fstab_stat_before_mount['stat']['checksum'] == fstab_stat_after_mount['stat']['checksum']
|
||||||
|
|
||||||
|
- name: Try to mount file B on file A mountpoint (should fail)
|
||||||
|
mount:
|
||||||
|
path: /tmp/myfs
|
||||||
|
src: '{{ ephemeral_device_B }}'
|
||||||
|
fstype: '{{ ephemeral_fstype }}'
|
||||||
|
state: ephemeral
|
||||||
|
register: ephemeral_mount_b_info
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Get third mount record (should be the same than the second)
|
||||||
|
shell: mount -v | grep '/tmp/myfs'
|
||||||
|
register: ephemeral_mount_record_3
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- name: Get mountinfo
|
||||||
|
shell: mount -v | awk '{print $3}' | grep '^/tmp/myfs$' | wc -l
|
||||||
|
register: check_mountinfo
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- name: Try to stat our test file
|
||||||
|
stat:
|
||||||
|
path: /tmp/myfs/test_file
|
||||||
|
register: test_file_stat
|
||||||
|
|
||||||
|
- name: Assert that mounting FS B over FS A failed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- check_mountinfo.stdout|int == 1
|
||||||
|
- ephemeral_mount_record_2.stdout == ephemeral_mount_record_3.stdout
|
||||||
|
- test_file_stat['stat']['exists']
|
||||||
|
- ephemeral_mount_b_info is failed
|
||||||
|
|
||||||
|
- name: Unmount FS with state = unmounted
|
||||||
|
mount:
|
||||||
|
path: /tmp/myfs
|
||||||
|
state: unmounted
|
||||||
|
|
||||||
|
- name: Get fstab checksum after unmounting an ephemeral mount with state = unmounted
|
||||||
|
stat:
|
||||||
|
path: '{{ ephemeral_fstab }}'
|
||||||
|
register: fstab_stat_after_unmount
|
||||||
|
|
||||||
|
- name: Get mountinfo
|
||||||
|
shell: mount -v | awk '{print $3}' | grep '^/tmp/myfs$' | wc -l
|
||||||
|
register: check_mountinfo
|
||||||
|
changed_when: no
|
||||||
|
|
||||||
|
- name: Try to stat our test file
|
||||||
|
stat:
|
||||||
|
path: /tmp/myfs/test_file
|
||||||
|
register: test_file_stat
|
||||||
|
|
||||||
|
- name: Assert that fstab is unchanged after unmounting an ephemeral mount with state = unmounted
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- check_mountinfo.stdout|int == 0
|
||||||
|
- not test_file_stat['stat']['exists']
|
||||||
|
- fstab_stat_before_mount['stat']['checksum'] == fstab_stat_after_unmount['stat']['checksum']
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Unmount potential failure relicas
|
||||||
|
mount:
|
||||||
|
path: /tmp/myfs
|
||||||
|
state: unmounted
|
||||||
|
|
||||||
|
- name: Remove loop devices on Solaris and BSD
|
||||||
|
ansible.builtin.shell: "{{ ephemeral_remove_loop_dev_cmd }}"
|
||||||
|
when: ephemeral_remove_loop_dev_cmd is defined
|
||||||
|
|
||||||
|
- name: Remove the test FS
|
||||||
|
file:
|
||||||
|
path: '{{ item }}'
|
||||||
|
state: absent
|
||||||
|
loop:
|
||||||
|
- /tmp/myfs_A.img
|
||||||
|
- /tmp/myfs_B.img
|
||||||
|
- /tmp/myfs
|
||||||
|
when: ansible_system in ('Linux', 'SunOS', 'FreeBSD', 'NetBSD', 'OpenBSD')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue