Add zfs_pool_mode: file|single|mirror. - file (default): loopback disk image at zfs_pool_file_path — real ZFS with no spare disk, ideal for a cost-optimized test VM; wipes nothing. - single/mirror: whole spare disk(s); mirror for production redundancy. Guard/probe now loops over zfs_pool_disks. Update group_vars, README (modes, prerequisites, safety), and CLAUDE.md current-focus note. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
92 lines
3.4 KiB
YAML
92 lines
3.4 KiB
YAML
---
|
|
- name: Install ZFS userland + kernel module
|
|
ansible.builtin.apt:
|
|
name: zfsutils-linux
|
|
state: present
|
|
|
|
- name: Ensure the ZFS kernel module is loaded
|
|
community.general.modprobe:
|
|
name: zfs
|
|
state: present
|
|
|
|
# --- Pool creation (guarded & destructive) ----------------------------------
|
|
- name: Check whether the ZFS pool already exists
|
|
ansible.builtin.command: "zpool list -H -o name {{ zfs_pool_name }}"
|
|
register: zpool_check
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Record pool existence
|
|
ansible.builtin.set_fact:
|
|
zpool_exists: "{{ zpool_check.rc == 0 }}"
|
|
|
|
# --- File mode: loopback disk image (no spare disk needed) ------------------
|
|
- name: Ensure the backing-file directory exists (file mode)
|
|
ansible.builtin.file:
|
|
path: "{{ zfs_pool_file_path | dirname }}"
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0700"
|
|
when: not zpool_exists and zfs_pool_mode == 'file'
|
|
|
|
- name: Create the sparse backing file (file mode)
|
|
ansible.builtin.command: "truncate -s {{ zfs_pool_file_size }} {{ zfs_pool_file_path }}"
|
|
args:
|
|
creates: "{{ zfs_pool_file_path }}"
|
|
when: not zpool_exists and zfs_pool_mode == 'file'
|
|
|
|
- name: Create the ZFS pool on the backing file (file mode)
|
|
ansible.builtin.command: >-
|
|
zpool create -o ashift=12
|
|
-O compression={{ zfs_compression }}
|
|
-O atime=off -O xattr=sa -O acltype=posixacl
|
|
-O mountpoint=/{{ zfs_pool_name }}
|
|
{{ zfs_pool_name }} {{ zfs_pool_file_path }}
|
|
when: not zpool_exists and zfs_pool_mode == 'file'
|
|
|
|
# --- Disk modes: single / mirror (guarded & destructive) --------------------
|
|
- name: Probe the target disks for existing data (disk modes)
|
|
ansible.builtin.command: "lsblk -nro FSTYPE,MOUNTPOINT,PARTTYPE {{ item }}"
|
|
register: disk_probes
|
|
changed_when: false
|
|
loop: "{{ zfs_pool_disks }}"
|
|
when: not zpool_exists and zfs_pool_mode in ['single', 'mirror']
|
|
|
|
- name: Refuse to create a pool on a non-empty disk unless forced
|
|
ansible.builtin.assert:
|
|
that:
|
|
- (item.stdout | trim | length == 0) or zfs_pool_force
|
|
fail_msg: >-
|
|
{{ item.item }} appears to already contain data ({{ item.stdout | trim }}).
|
|
Refusing to create the pool. Verify the device, then set zfs_pool_force=true.
|
|
loop: "{{ disk_probes.results | default([]) }}"
|
|
loop_control:
|
|
label: "{{ item.item | default('') }}"
|
|
when: not zpool_exists and zfs_pool_mode in ['single', 'mirror']
|
|
|
|
- name: Create the ZFS pool on the dedicated disk(s) (disk modes)
|
|
ansible.builtin.command: >-
|
|
zpool create {{ '-f ' if zfs_pool_force else '' }}-o ashift=12
|
|
-O compression={{ zfs_compression }}
|
|
-O atime=off -O xattr=sa -O acltype=posixacl
|
|
-O mountpoint=/{{ zfs_pool_name }}
|
|
{{ zfs_pool_name }}
|
|
{{ 'mirror ' if zfs_pool_mode == 'mirror' else '' }}{{ zfs_pool_disks | join(' ') }}
|
|
when: not zpool_exists and zfs_pool_mode in ['single', 'mirror']
|
|
|
|
# --- Datasets ---------------------------------------------------------------
|
|
- name: List existing datasets
|
|
ansible.builtin.command: "zfs list -H -o name"
|
|
register: zfs_existing
|
|
changed_when: false
|
|
|
|
- name: Create platform + customers datasets
|
|
ansible.builtin.command: >-
|
|
zfs create -p
|
|
{% if item.mountpoint is defined %}-o mountpoint={{ item.mountpoint }}{% endif %}
|
|
{{ zfs_pool_name }}/{{ item.path }}
|
|
loop: "{{ zfs_child_datasets }}"
|
|
loop_control:
|
|
label: "{{ zfs_pool_name }}/{{ item.path }}"
|
|
when: (zfs_pool_name ~ '/' ~ item.path) not in zfs_existing.stdout_lines
|