fix(tasks): remove the btrfs subvolume of a deleted unix user
Deleting a user whose home is a btrfs subvolume left that subvolume behind. The role passed remove=true to the user module, but userdel removes a home directory with rmdir, which refuses to delete a subvolume that still holds nested subvolumes or is otherwise not empty. The home therefore survived the removal and blocked a later recreation of the same user, because btrfs_subvolume then found the path already occupied. The subvolume is now deleted explicitly by the same module that created it, which keeps the creation and the removal symmetric. Snapshots are stored outside the subvolume, so a btrbk based backup keeps the data available even though the home itself is gone. The removal is skipped when the home directory no longer exists, since findmnt fails on a missing path. Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -34,6 +34,10 @@ unix_users:
|
||||
Optionally, the home directory of a user can also be created as dedicated btrfs subvolume. This make it possible to
|
||||
create snapshots of the home directory, for example via `btrbk`.
|
||||
|
||||
> [!WARNING]
|
||||
> Removing a user with `state: absent` also deletes the btrfs subvolume of the home directory. Snapshots taken from that
|
||||
> subvolume are not removed and keep the data available.
|
||||
|
||||
```yaml
|
||||
unix_users:
|
||||
toor:
|
||||
|
||||
@@ -1,7 +1,37 @@
|
||||
---
|
||||
|
||||
- name: Remove unix user {{ unix_user.key }}
|
||||
- name: "Define home directory for unix user: {{ unix_user.key }}"
|
||||
ansible.builtin.set_fact:
|
||||
_unix_users_home: "{{ unix_user.value.home | default('/home/' + unix_user.key) }}"
|
||||
|
||||
# userdel cannot remove a btrfs subvolume. Such a home is deleted afterwards via the btrfs_subvolume module.
|
||||
- name: "Remove unix user: {{ unix_user.key }}"
|
||||
ansible.builtin.user:
|
||||
name: "{{ unix_user.key }}"
|
||||
state: absent
|
||||
remove: true
|
||||
remove: "{{ not (unix_user.value.btrfs | default(false)) }}"
|
||||
|
||||
- name: "Remove btrfs home of unix user: {{ unix_user.key }}"
|
||||
when: unix_user.value.btrfs is defined and
|
||||
unix_user.value.btrfs
|
||||
block:
|
||||
- name: "Stat home directory"
|
||||
ansible.builtin.stat:
|
||||
path: "{{ _unix_users_home }}"
|
||||
register: _unix_users_home_stat
|
||||
|
||||
# findmnt fails on a missing path, so the device is only determined as long as the home directory exists.
|
||||
- name: "Delete btrfs subvolume of an existing home directory"
|
||||
when: _unix_users_home_stat.stat.exists
|
||||
block:
|
||||
- name: "Find btrfs device"
|
||||
ansible.builtin.command:
|
||||
cmd: /bin/bash -c "findmnt -no SOURCE -T {{ _unix_users_home }} | sed 's/\[.*\]//'"
|
||||
register: _unix_users_btrfs_device
|
||||
changed_when: false
|
||||
|
||||
- name: "Delete btrfs subvolume: {{ _unix_users_home }}"
|
||||
community.general.btrfs_subvolume:
|
||||
filesystem_device: "{{ _unix_users_btrfs_device.stdout }}"
|
||||
name: "{{ _unix_users_home }}"
|
||||
state: absent
|
||||
|
||||
Reference in New Issue
Block a user