chore: first commit

This commit is contained in:
Clément Désiles
2025-07-25 20:23:54 +02:00
parent 5c4016357f
commit c612cc7839
88 changed files with 3255 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
# Disks
Ansible community support for ZFS is limited to create filesystems, volumes and snapshots. There is no support for managing zpools, so here it is.
## Inventory
Here is an example inventory file you can use with this role:
```yaml
zfs_pools:
- name: peace
type: raidz1
devices:
- ata-SOME-DISK-LABEL-1
- ata-SOME-DISK-LABEL-2
options:
ashift: 12
root: /mnt/peace
state: present
```
And you will get raid1 zpool peace with two disks, with 12 ashift.
You can use a variety of options, see the [zpoolprops(7)](https://openzfs.github.io/openzfs-docs/man/master/7/zpoolprops.7.html) man page.
And for your zfs filesystems:
```yaml
zfs_datasets:
- name: peace/pictures
state: present
- name: peace/movies
state: present
extra_zfs_properties:
mountpoint: /mnt/peace/movies
quota: 500G
```
## References
- https://docs.ansible.com/ansible/latest/collections/community/general/zfs_module.html
- https://github.com/mrlesmithjr/ansible-zfs/blob/master/tasks/manage_zfs.yml
- https://wiki.archlinux.org/title/ZFS
View File
+16
View File
@@ -0,0 +1,16 @@
---
# due to Ansible limitations, we cannot loop over a block, so we loop over a distinct tasks file...
# @see https://stackoverflow.com/a/58911694
- name: set ownership on dataset mountpoint
block:
- name: get the mountpoint
ansible.builtin.shell: "zfs get -H -o value mountpoint {{ dataset.name }}"
register: mountpoint
changed_when: false
- name: set owner of mountpoints
file:
path: "{{ mountpoint.stdout }}"
owner: "{{ dataset.user | default(main_user) }}"
group: "{{ dataset.group | default(main_user) }}"
state: directory
recurse: true
+25
View File
@@ -0,0 +1,25 @@
---
# see: https://docs.ansible.com/ansible/latest/collections/community/general/zfs_module.html
- name: managing filesystems, volumes, snapshots
zfs:
name: "{{ item.name }}"
state: "{{ item.state }}"
extra_zfs_properties: "{{ item.extra_zfs_properties|default(omit) }}"
origin: "{{ item.origin|default(omit) }}"
with_items: "{{ zfs_datasets }}"
- command:
cmd: whoami
no_log: true
become: false
register: main_user
- set_fact:
main_user: "{{ main_user.stdout }}"
no_log: true
- name: set dataset ownership
include_tasks: "./dataset-ownership.yml"
loop: "{{ zfs_datasets }}"
loop_control:
loop_var: dataset
+12
View File
@@ -0,0 +1,12 @@
---
# due to Ansible limitations, we cannot loop over a block, so we loop over a distinct tasks file...
# @see https://stackoverflow.com/a/58911694
- name: prompt the user for confirmation
ansible.builtin.pause:
prompt: "[IRREVERSIBLE] Are you sure you want to delete zpool {{ zpool.name }}?"
echo: yes
register: confirmation
- name: deleting zpool
ansible.builtin.command: "zpool destroy {{ zpool.name }}"
when: confirmation.user_input | lower in ['yes', 'y']
+91
View File
@@ -0,0 +1,91 @@
---
- name: Check if zfs-linux-lts is installed
command: pacman -Qi zfs-dkms
register: zfs_dkms_installed
changed_when: false
failed_when: false
- name: Install zfs
when: zfs_dkms_installed.stderr
block:
- name: disable SUDOERS password prompt for makepkg
no_log: true
lineinfile:
dest: /etc/sudoers
state: present
regexp: "^#?%wheel"
line: "%wheel ALL=(ALL) NOPASSWD: ALL"
validate: /usr/sbin/visudo -cf %s
# Note: I successfully tried zfs-linux-lts and zfs-linux-lts-headers, but
# the next kernel upgrade failed: cyclic dependency.
# Using dkms with the lts linux kernel is a better approach IMO.
- name: Install zfs
become: false
command:
cmd: "paru -S --noconfirm zfs-dkms zfs-utils"
- name: Restore SUDOERS password prompt after yay
no_log: true
lineinfile:
dest: /etc/sudoers
state: present
regexp: "^#?%wheel"
line: "%wheel ALL=(ALL:ALL) ALL"
validate: /usr/sbin/visudo -cf %s
- name: check if /etc/hostid is present
stat:
path: /etc/hostid
register: hostid
changed_when: false
- name: generate /etc/hostid if not present
when: not hostid.stat.exists
command: zgenhostid $(hostid)
- name: Check if zrepl is installed
command: pacman -Qi zrepl
register: zrepl_installed
changed_when: false
failed_when: false
- name: Install zrepl
when: zrepl_installed.stderr
block:
- name: disable SUDOERS password prompt for makepkg
no_log: true
lineinfile:
dest: /etc/sudoers
state: present
regexp: "^#?%wheel"
line: "%wheel ALL=(ALL) NOPASSWD: ALL"
validate: /usr/sbin/visudo -cf %s
- name: Install zrepl
become: false
command:
cmd: "paru -S --noconfirm zrepl"
- name: Restore SUDOERS password prompt after paru
no_log: true
lineinfile:
dest: /etc/sudoers
state: present
regexp: "^#?%wheel"
line: "%wheel ALL=(ALL:ALL) ALL"
validate: /usr/sbin/visudo -cf %s
- name: Enable zfs services
service:
name: "{{ item }}"
enabled: true
state: started
loop:
- zfs.target
- zfs-import.target
- zfs-volumes.target
- zfs-import-scan.service
- zfs-volume-wait.service
# Please note /etc/zfs/zpool.cache should not be present, as it is deprecated
# and we are using zfs-import-scan.service, which rely on blkid.
+9
View File
@@ -0,0 +1,9 @@
---
- name: Install ZFS
include_tasks: install.yml
- name: Configure Zpools
include_tasks: pools.yml
- name: "Setup ZFS datasets: filesystems, snapshots, volumes"
include_tasks: datasets.yml
+47
View File
@@ -0,0 +1,47 @@
---
# tasks file for zfs management
# Based on: https://github.com/mrlesmithjr/ansible-zfs/blob/master/tasks/manage_zfs.yml
# Expected variables in your inventory: zfs_pools.
- name: checking existing zpool(s)
ansible.builtin.shell: "zpool list -H -o name"
changed_when: false
register: current_zp_state
check_mode: no
when: zfs_pools is defined
- name: gather zpool status
ansible.builtin.shell: zpool status
changed_when: false
register: zpool_devices
when: zfs_pools is defined
- name: creating basic zpool(s)
ansible.builtin.command: "zpool create {{ '-o '+ item.options.items() |map('join', '=') | join (' -o ') if item.options is defined else '' }} {{ item.name }} {{ item.devices|join (' ') }}"
with_items: "{{ zfs_pools }}"
when:
- zfs_pools is defined
- item.type == "basic"
- item.name not in current_zp_state.stdout
- item.state == "present"
- item.devices[0] not in zpool_devices.stdout
- name: creating mirror/zraid zpool(s)
ansible.builtin.command: "zpool create {{ '-o '+ item.options.items() |map('join', '=') | join (' -o ') if item.options is defined else '' }} {{ item.name }} {{ item.type }} {{ item.devices|join (' ') }}"
with_items: "{{ zfs_pools }}"
when:
- zfs_pools is defined
- item.type != "basic"
- item.name not in current_zp_state.stdout
- item.state == "present"
- item.devices[0] not in zpool_devices.stdout
- name: deleting zpool(s) with care
include_tasks: "./delete-pool.yml"
when:
- zfs_pools is defined
- zpool.name in current_zp_state.stdout_lines
- zpool.state == "absent"
loop: "{{ zfs_pools }}"
loop_control:
loop_var: zpool