Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelogs/fragments/569_keep_mountpoint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
minor_changes:
- keep_mountpoint - added keep_mountpoint option with default value false. If set to true keep_mountpoint changes the behaviour of state\: absent by keeping the mountpoint.
33 changes: 31 additions & 2 deletions plugins/modules/mount.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@
real source. V(absent) does not unmount recursively, and the module will
fail if multiple devices are mounted on the same mount point. Using
V(absent) with a mount point that is not registered in the I(fstab) has
no effect, use V(unmounted) instead.
no effect, use V(unmounted) instead. You can set O(keep_mountpoint) to
True to keep the mountpoint.
- V(remounted) specifies that the device will be remounted for when you
want to force a refresh on the mount itself (added in 2.9). This will
always return RV(ignore:changed=true). If O(opts) is set, the options will be
Expand Down Expand Up @@ -132,6 +133,16 @@
the original file back if you somehow clobbered it incorrectly.
type: bool
default: false
keep_mountpoint:
description:
- Change the default behaviour of state=absent by keeping the mountpoint
- With keep_mountpoint=true, state=absent is like unmounted plus the
fstab update.
- Use it if you care about finding original mountpoint content without failing
and want to remove the entry in fstab. If you have no entry to clean in
fstab you can use state=unmounted
type: bool
default: false
notes:
- As of Ansible 2.3, the O(name) option has been changed to O(path) as
default, but O(name) still works as well.
Expand Down Expand Up @@ -175,6 +186,23 @@
path: /tmp/mnt-pnt
state: remounted

# The following will fail on first run
# if /home/mydir is not empty after unmounting,
# though unmount and remove from fstab are successfull.
# It will be successfull on subsequent runs (already unmounted).
- name: Unmount and remove from fstab, then if unmount was necessary try to remove mountpoint /home/mydir
ansible.posix.mount:
path: /home/mydir
state: absent
# The following will not fail on first run
# if /home/mydir is not empty after unmounting.
# It will leave /home/mydir and its content (if any) after unmounting.
- name: Unmount and remove from fstab, but keep /home/mydir
ansible.posix.mount:
path: /home/mydir
state: absent
keep_mountpoint: true

# The following will not save changes to fstab, and only be temporary until
# a reboot, or until calling "state: unmounted" followed by "state: mounted"
# on the same "path"
Expand Down Expand Up @@ -779,6 +807,7 @@ def main():
src=dict(type='path'),
backup=dict(type='bool', default=False),
state=dict(type='str', required=True, choices=['absent', 'absent_from_fstab', 'mounted', 'present', 'unmounted', 'remounted', 'ephemeral']),
keep_mountpoint=dict(type='bool', default=False),
),
supports_check_mode=True,
required_if=(
Expand Down Expand Up @@ -899,7 +928,7 @@ def main():
module.fail_json(
msg="Error unmounting %s: %s" % (name, msg))

if os.path.exists(name):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will change the behavior of state: absent.
But I don't think the rmdir logic should be skipped. Because it breaks backward compatibility.
If you want to skip it, how about adding keep_mountpoint or preserve_mountpoint to keep the mountpoint to avoid Directory not empty error instead of removing this section.

If this is set as true, you can skip rmdir section. Also, if the default value is set as false, to keep backward compatibility, you can set it to false by default.

if os.path.exists(name) and module.params['keep_mountpoint'] is False:
try:
os.rmdir(name)
except (OSError, IOError) as e:
Expand Down
82 changes: 82 additions & 0 deletions tests/integration/targets/mount/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -789,3 +789,85 @@
loop:
- /tmp/myfs.img
- /tmp/myfs

- name: Block to test keep_mountpoint option
block:
- name: Create the mount point
ansible.builtin.file:
state: directory
path: '/tmp/myfs'
mode: '0755'

- name: Create empty file for FS aaa
community.general.filesize:
path: /tmp/myfs.img
size: 20M

- name: Format FS bbb
community.general.filesystem:
fstype: xfs
dev: /tmp/myfs.img

- name: Put data in the mount point before mounting
ansible.builtin.copy:
content: 'Testing
This is the data before mounting
'
dest: '/tmp/myfs/test_file'
mode: '0644'
register: file_before_info

- name: Mount with fstab
ansible.posix.mount:
path: '/tmp/myfs'
fstype: xfs
state: mounted
src: '/tmp/myfs.img'

- name: Check data disappears - stat data
ansible.builtin.stat:
path: '/tmp/myfs/test_file'
register: file_stat_after_mount
- name: Check data disappears - file does not exist
ansible.builtin.assert:
that:
- file_stat_after_mount['stat']['exists'] == false
- name: Put data in the mount point after mounting
ansible.builtin.copy:
content: 'Testing
This is the data updated after mounting
'
dest: '/tmp/myfs/test_file'
mode: '0644'
register: file_after_info
- name: Umount with keep_mountpoint
ansible.posix.mount:
path: '/tmp/myfs'
fstype: xfs
state: absent
keep_mountpoint: true
- name: Check original data reappears - stat data
ansible.builtin.stat:
path: '/tmp/myfs/test_file'
register: file_stat_after_umount
- name: Check original data reappears - compare checksums
ansible.builtin.assert:
that:
- file_stat_after_umount['stat']['checksum'] == file_before_info['checksum']
always:
- name: Remove the first test file
ansible.builtin.file:
path: /tmp/myfs/test_file
state: absent
- name: Unmount FS
ansible.posix.mount:
path: /tmp/myfs
state: absent
- name: Remove the test FS and the second test file
ansible.builtin.file:
path: '{{ item }}'
state: absent
loop:
- /tmp/myfs/test_file
- /tmp/myfs.img
- /tmp/myfs
Loading