95 lines
3.2 KiB
YAML

---
# roles/storage_mounts/tasks/main.yml
#
# Idempotent NFS mount configuration for lab VMs.
# Safe to run on already-mounted hosts — ansible.posix.mount checks current
# kernel mount table and fstab before making any change.
# --------------------------------------------------
# STEP 1: Install NFS client packages
# WHY ansible.builtin.apt (not shell): idempotent; only installs when absent.
# --------------------------------------------------
- name: Install NFS client package
ansible.builtin.apt:
name: nfs-common
state: present
update_cache: true
tags: [storage, packages]
# --------------------------------------------------
# STEP 2: Create mount point directories
# WHY before fstab: mount points must pre-exist before systemd or mount(8)
# can act on them. file module is idempotent on existing dirs.
# --------------------------------------------------
- name: Ensure NFS mount point directories exist
ansible.builtin.file:
path: "{{ item.dest }}"
state: directory
mode: '0755'
owner: root
group: root
loop: "{{ storage_nfs_mounts }}"
tags: [storage, filesystem]
# --------------------------------------------------
# STEP 3: Write fstab entries
# WHY state: present (not mounted): separates "persist across reboots"
# from "mount now". The next task handles the live mount separately so
# each concern has a clear changed/ok signal.
# --------------------------------------------------
- name: Write NFS entries to /etc/fstab
ansible.posix.mount:
src: "{{ storage_nfs_server }}:{{ item.src }}"
path: "{{ item.dest }}"
fstype: nfs
opts: "{{ item.opts }}"
state: present
loop: "{{ storage_nfs_mounts }}"
tags: [storage, fstab]
# --------------------------------------------------
# STEP 4: Mount NFS shares in the live kernel
# WHY state: mounted: issues mount(8) if not already in the mount table.
# No-op when the share is already mounted; changed only on first run
# or after an unmount.
# --------------------------------------------------
- name: Mount NFS shares
ansible.posix.mount:
src: "{{ storage_nfs_server }}:{{ item.src }}"
path: "{{ item.dest }}"
fstype: nfs
opts: "{{ item.opts }}"
state: mounted
loop: "{{ storage_nfs_mounts }}"
tags: [storage, mount]
# --------------------------------------------------
# STEP 5: Verify mounts are reachable
# WHY stat (not ls): stat is a builtin module with no external dependency;
# it checks that the path exists AND is a directory (not an empty
# local dir masquerading as a successful mount point).
# --------------------------------------------------
- name: Verify NFS mount points are accessible
ansible.builtin.stat:
path: "{{ item.dest }}"
register: storage_mounts_stat
loop: "{{ storage_nfs_mounts }}"
tags: [storage, verify]
- name: Assert NFS mount points are directories
ansible.builtin.assert:
that:
- item.stat.exists
- item.stat.isdir
fail_msg: >-
NFS mount point {{ item.item.dest }} is not accessible after mount attempt.
Check NFS server ({{ storage_nfs_server }}) connectivity and export paths.
loop: "{{ storage_mounts_stat.results }}"
when: not ansible_check_mode
tags: [storage, verify]