400 Configure ZFS
Use case
Use the role vbotka.freebsd.zfs to configure ZFS pools and datasets.
Tree
shell > tree .
.
├── ansible.cfg
├── host_vars
│ └── iocage_04
│ ├── loader.yml
│ └── zfs.yml
├── iocage.ini
├── pb-loader.yml
└── pb-zfs.yml
Synopsis
At the managed host
iocage_04create ZFS pools:
zrootiocage
create and mount ZFS datasets:
zroot/exportmount /exportiocage/portsmount /usr/portsiocage/srcmount /usr/srciocage/objmount /usr/objiocage/poudrieremount /usr/local/poudriere
Requirements
role vbotka.freebsd.zfs
Notes
The role vbotka.freebsd.postinstall is used to configure /boot/loader.conf
Note
Known issues
The module community.general.zpool can’t create correct diff. For example,
(Pdb) p vdev_layout_diff
{'before': {'vdevs': [{'type': 'stripe', 'disks': ['/dev/ada2']}, {'type': 'stripe', 'disks': ['/dev/ada3']}]},
'after': {'vdevs': [{'type': 'stripe', 'disks': ['/dev/ada2', '/dev/ada3']}]}}
This makes the module not idempotent. It crashes when running repeatedly. For example,
failed: [srv.example.org] (item=iocage) =>
ansible_loop_var: item
changed: false
cmd: /sbin/zpool add iocage /dev/ada2 /dev/ada3
item:
key: iocage
value:
vdevs:
- disks:
- /dev/ada2
- /dev/ada3
msg: |-
invalid vdev specification
use '-f' to override the following errors:
/dev/ada2 is part of active pool 'iocage'
/dev/ada3 is part of active pool 'iocage'
rc: 1
...
Setting force: true doesn’t help. At the moment, the only workaround is to skip the module if
the pool already exists. You’ll see a warning. For example,
TASK [vbotka.freebsd_zfs : Pools: WARNING | community.general.zpool skipped.] ****
ok: [srv.example.org] =>
msg: |-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# WARNING:
#
# The module community.general.zpool is not idempotent. It crashes
# when running repeatedly. Because of the poor quality, the module
# community.general.zpool will be skipped for pools:
# ['iocage']
#
# Configure the skipped pools manually, if necessary.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ansible.cfg
[defaults]
gathering = explicit
callback_result_format = yaml
display_skipped_hosts = false
[connection]
pipelining = true
Inventory iocage.ini
iocage_04 ansible_host=10.1.0.29
[iocage]
iocage_04
[iocage:vars]
ansible_user=admin
ansible_become=true
ansible_python_interpreter=auto_silent
host_vars
fp_loader_conf_template: ''
fp_loader_conf:
- name: vfs.zfs.prefetch.disable
value: "0"
fzfs_enable: true
fzfs_pools:
zroot:
vdevs:
- disks: [/dev/ada0p4, /dev/ada1p4]
iocage:
vdevs:
- disks: [/dev/ada2, /dev/ada3]
fzfs_manage:
- name: zroot/export
state: present
extra_zfs_properties:
compression: 'on'
mountpoint: /export
- name: iocage/ports
state: present
extra_zfs_properties:
compression: 'on'
mountpoint: /usr/ports
- name: iocage/src
state: present
extra_zfs_properties:
compression: 'on'
mountpoint: /usr/src
- name: iocage/obj
state: present
extra_zfs_properties:
compression: 'on'
mountpoint: /usr/obj
- name: iocage/poudriere
state: present
extra_zfs_properties:
compression: 'on'
mountpoint: /usr/local/poudriere
Playbook pb-loader.yml
- name: Configure loader.conf
hosts: iocage
gather_facts: true
tasks:
- name: Configure loader.conf
ansible.builtin.import_role:
name: vbotka.freebsd.postinstall
tasks_from: loader
Playbook output - loader.conf
(env) > ansible-playbook pb-loader.yml -i iocage.ini
PLAY [Configure loader.conf] ***************************************************
TASK [Gathering Facts] *********************************************************
ok: [iocage_04]
TASK [vbotka.freebsd.postinstall : Loader: Backup orig /boot/loader.conf] ******
ok: [iocage_04]
TASK [vbotka.freebsd.postinstall : Loader: Configure by sysctl /boot/loader.conf] ***
ok: [iocage_04] => (item={'name': 'vfs.zfs.prefetch.disable', 'value': '0'})
TASK [vbotka.freebsd.postinstall : Loader: Get sysctls settable via loader.] ***
ok: [iocage_04]
PLAY RECAP *********************************************************************
iocage_04 : ok=4 changed=0 unreachable=0 failed=0 skipped=5 rescued=0 ignored=0
Note
Reboot if you see the message
[MESSAGE] Reboot to activate configuration in /boot/loader.conf
Playbook pb-zfs.yml
- name: Configure ZFS.
hosts: iocage
gather_facts: true
roles:
- vbotka.freebsd.zfs
Playbook output - Display variables
(env) > ansible-playbook pb-zfs.yml -i iocage.ini -t fzfs_debug -e fzfs_debug=true
PLAY [Configure ZFS.] **********************************************************
TASK [Gathering Facts] *********************************************************
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Debug fzfs_debug=true] ******************************
ok: [iocage_04] =>
msg: |-
fzfs_role_version: 2.8.2
ansible_role_name: vbotka.freebsd.zfs
ansible_facts.architecture: amd64
ansible_facts.os_family: FreeBSD
ansible_facts.distribution: FreeBSD
ansible_facts.distribution_major_version: 15
ansible_facts.distribution_version: 15.0
ansible_facts.distribution_release: 15.0-RELEASE-p1
ansible_facts.python_version: 3.11.14
fzfs_enable: True
fzfs_debug2: False
fzfs_pools_sanity: True
fzfs_assert_quiet: True
fzfs_facts_ds: False
fzfs_facts_recurse: True
fzfs_mount_all: True
fzfs_sysctl_tuneables_warning: "True"
fzfs_sysctl_conf:
[]
fzfs_rcconf:
[]
fzfs_pools:
iocage:
vdevs:
- disks: [/dev/ada2, /dev/ada3]
zroot:
vdevs:
- disks: [/dev/ada0p4, /dev/ada1p4]
fzfs_manage:
- extra_zfs_properties: {compression: 'on', mountpoint: /export}
name: zroot/export
state: present
- extra_zfs_properties: {compression: 'on', mountpoint: /usr/ports}
name: iocage/ports
state: present
- extra_zfs_properties: {compression: 'on', mountpoint: /usr/src}
name: iocage/src
state: present
- extra_zfs_properties: {compression: 'on', mountpoint: /usr/obj}
name: iocage/obj
state: present
- extra_zfs_properties: {compression: 'on', mountpoint: /usr/local/poudriere}
name: iocage/poudriere
state: present
fzfs_mountpoints:
[]
PLAY RECAP *********************************************************************
iocage_04 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Playbook output - Configure ZFS
(env) > ansible-playbook pb-zfs.yml -i iocage.ini
PLAY [Configure ZFS.] **********************************************************
TASK [Gathering Facts] *********************************************************
ok: [iocage_04]
TASK [Sysctl: Include vbotka.freebsd.postinstall sysctl] ***********************
included: vbotka.freebsd.postinstall for iocage_04
TASK [vbotka.freebsd.postinstall : Sysctl: Get sysctls settable via loader.] ***
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Rcconf: Enable and Start zfs] ***********************
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Pools: Get zpool status.] ***************************
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Pools: Sanity: No fzfs_pools disks already in other pools.] ***
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Pools: Sanity: No fzfs_pools disks already mounted.] ***
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Pools: Sanity: fzfs_pools disks are unique.] ********
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Pools: WARNING | community.general.zpool skipped.] ***
ok: [iocage_04] =>
msg: |-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# WARNING:
#
# The module community.general.zpool is not idempotent. It crashes
# when running repeatedly. Because of the poor quality, the module
# community.general.zpool will be skipped for pools:
# ['zroot', 'iocage']
#
# Configure the skipped pools manually, if necessary.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TASK [vbotka.freebsd.zfs : Facts: Run zpool_facts] *****************************
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Manage: Sanity all pools available.] ****************
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Manage: Manage zfs] *********************************
ok: [iocage_04] => (item=zroot/export)
ok: [iocage_04] => (item=iocage/ports)
ok: [iocage_04] => (item=iocage/src)
ok: [iocage_04] => (item=iocage/obj)
ok: [iocage_04] => (item=iocage/poudriere)
PLAY RECAP *********************************************************************
iocage_04 : ok=12 changed=0 unreachable=0 failed=0 skipped=15 rescued=0 ignored=0
Playbook output - List pools
(env) > ansible-playbook pb-zfs.yml -t fzfs_facts_pools -e fzfs_debug=true
PLAY [Configure ZFS.] **********************************************************
TASK [Gathering Facts] *********************************************************
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Facts: Run zpool_facts] *****************************
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Facts: Debug list pools fzfs_debug=true] ************
ok: [iocage_04] =>
msg: |-
fzfs_pools_required: ['iocage', 'zroot']
fzfs_pools_missing: []
fzfs_pools_present: ['iocage', 'zroot']
name: iocage size: 7.25T free: 7.24T
name: zroot size: 472G free: 465G
PLAY RECAP *********************************************************************
iocage_04 : ok=3 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Playbook output - List datasets
(env) > ansible-playbook pb-zfs.yml -t fzfs_facts_ds -e fzfs_facts_ds=true -e fzfs_debug=true
PLAY [Configure ZFS.] **********************************************************
TASK [Gathering Facts] *********************************************************
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Facts: Run zpool_facts] *****************************
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Facts: Run zfs_facts] *******************************
ok: [iocage_04] => (item=iocage)
ok: [iocage_04] => (item=zroot)
TASK [vbotka.freebsd.zfs : Facts: Get dictionary of datasets] ******************
ok: [iocage_04]
TASK [vbotka.freebsd.zfs : Facts: Debug list of datasets fzfs_debug=true] ******
ok: [iocage_04] =>
fzfs_datasets | to_nice_yaml: |-
iocage:
iocage: /iocage
iocage/iocage: /iocage/iocage
iocage/iocage/download: /iocage/iocage/download
iocage/iocage/download/14.3-RELEASE: /iocage/iocage/download/14.3-RELEASE
iocage/iocage/download/15.0-RELEASE: /iocage/iocage/download/15.0-RELEASE
iocage/iocage/images: /iocage/iocage/images
iocage/iocage/jails: /iocage/iocage/jails
iocage/iocage/log: /iocage/iocage/log
iocage/iocage/releases: /iocage/iocage/releases
iocage/iocage/releases/14.3-RELEASE: /iocage/iocage/releases/14.3-RELEASE
iocage/iocage/releases/14.3-RELEASE/root: /iocage/iocage/releases/14.3-RELEASE/root
iocage/iocage/releases/15.0-RELEASE: /iocage/iocage/releases/15.0-RELEASE
iocage/iocage/releases/15.0-RELEASE/root: /iocage/iocage/releases/15.0-RELEASE/root
iocage/iocage/releases/15.0-RELEASE/root@ansible_client: null
iocage/iocage/releases/15.0-RELEASE/root@ansible_client_apache: null
iocage/iocage/releases/15.0-RELEASE/root@ansible_client_pull: null
iocage/iocage/templates: /iocage/iocage/templates
iocage/iocage/templates/ansible_client: /iocage/iocage/templates/ansible_client
iocage/iocage/templates/ansible_client/root: /iocage/iocage/templates/ansible_client/root
iocage/iocage/templates/ansible_client_apache: /iocage/iocage/templates/ansible_client_apache
iocage/iocage/templates/ansible_client_apache/root: /iocage/iocage/templates/ansible_client_apache/root
iocage/iocage/templates/ansible_client_pull: /iocage/iocage/templates/ansible_client_pull
iocage/iocage/templates/ansible_client_pull/root: /iocage/iocage/templates/ansible_client_pull/root
iocage/obj: /usr/obj
iocage/ports: /usr/ports
iocage/poudriere: /usr/local/poudriere
iocage/src: /usr/src
zroot:
zroot: /zroot
zroot/ROOT: none
zroot/ROOT/default: /
zroot/export: /export
zroot/home: /home
zroot/home/admin: /home/admin
zroot/home/asadmin: /home/asadmin
zroot/tmp: /tmp
zroot/usr: /usr
zroot/usr/ports: /usr/ports
zroot/usr/src: /usr/src
zroot/var: /var
zroot/var/audit: /var/audit
zroot/var/crash: /var/crash
zroot/var/log: /var/log
zroot/var/mail: /var/mail
zroot/var/tmp: /var/tmp
PLAY RECAP *********************************************************************
iocage_04 : ok=5 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0