commit 4ebc67f2304f4af373379d8901d8ca049ed207f0 Author: Josh Lay Date: Sat Oct 18 16:44:11 2025 -0500 init diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f1428e --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +zfs\_dkms +========= + +Manages [ZFS on Linux](https://zfsonlinux.org/) +for [Red Hat/derivatives](https://openzfs.github.io/openzfs-docs/Getting%20Started/RHEL-based%20distro/index.html), +[Debian](https://openzfs.github.io/openzfs-docs/Getting%20Started/Debian/index.html), +and [Ubuntu](https://openzfs.github.io/openzfs-docs/Getting%20Started/Ubuntu/index.html) + +Requirements +------------ + +None. + +Role Variables +-------------- + +| Variable | Description | Default _(Role)_ | Default _(Kernel/Upstream)_ | +|----------|:-----------:|--------:|--------:| +| `zfs_dkms_arc_pct_min` | Minimum physical memory (%) allowed for ARC usage | `0` | `0` | +| `zfs_dkms_arc_pct_max` | Max physical memory (%) allowed for ARC usage | `16` | `0` | +| `zfs_dkms_timeout` | Seconds to wait while rebooting `RHEL`/derivatives
_[for kernel update and current headers]_ | `3600` | _N/A_ | + +Dependencies +------------ + +1. `community.general` + +Example Playbook +---------------- + + - hosts: servers + roles: + - { role: zfs_dkms } + +License +------- + +Apache-2.0 diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..bcfd17d --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,7 @@ +--- +# defaults file for zfs_dkms +# + +zfs_dkms_timeout: 3600 # EL-based hosts are rebooted to ensure the module is available/built; skipped if present/Debian-based +zfs_dkms_arc_pct_min: 0 +zfs_dkms_arc_pct_max: 16 diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..a8f4275 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,8 @@ +--- +# handlers file for zfs_dkms + +- name: Reboot into new Kernel + listen: zfs_dkms_reboot + ansible.builtin.reboot: + reboot_timeout: "{{ zfs_dkms_timeout }}" # default 3600 + become: true diff --git a/meta/argument_specs.yml b/meta/argument_specs.yml new file mode 100644 index 0000000..8943207 --- /dev/null +++ b/meta/argument_specs.yml @@ -0,0 +1,28 @@ +--- +argument_specs: + # roles/zfs_dkms/tasks/main.yml entry point + main: + short_description: Entrypoint for the 'zfs_dkms' role + description: + - ZFS on Linux + author: + - Josh Lay + options: + zfs_dkms_timeout: + type: "int" + required: false + default: 3600 + description: + - "How long to wait when rebooting RHEL/derivatives for kernel updates [and current headers]" + zfs_dkms_arc_pct_min: + type: "int" + required: false + default: 0 + description: + - "Minimum physical memory (%) allowed for ARC usage" + zfs_dkms_arc_pct_max: + type: "int" + required: false + default: 16 + description: + - "Max physical memory (%) allowed for ARC usage" diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..650abfd --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,21 @@ +galaxy_info: + author: Josh Lay + description: ZFS on Linux + # company: your company (optional) + namespace: joshlay + + # If the issue tracker for your role is not on github, uncomment the + # next line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + license: Apache-2.0 + + min_ansible_version: '2.1' + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + galaxy_tags: + - zfs + +dependencies: [] diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..0804e39 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,99 @@ +--- +# tasks file for zfs_dkms +# +# NOTE: limited EL8 testing/coverage, ansible-core 2.17+ lacks support for Python 3.6 +# [managing Python releases considered out of scope] + +- name: Package Facts + ansible.builtin.package_facts: { manager: auto } + +- name: Look for module + ansible.builtin.stat: { path: /sys/module/zfs } + register: zfs_dkms_dir + +- name: Debian/Apt Tasks + when: ansible_os_family == 'Debian' + block: + - name: Apt Backport Sources | {{ ansible_distribution_release }} + loop: "{{ (zfs_dkms_deb_backports[ansible_distribution_release | lower]) | default([]) }}" + loop_control: { loop_var: repo } + become: true + ansible.builtin.apt_repository: { repo: "{{ repo }}", filename: "{{ ansible_distribution_release }}-backports", state: present } + + - name: Pin ZFS to Backports (Debian) + when: + - zfs_dkms_deb_backports[ansible_distribution_release | lower] is defined + - zfs_dkms_deb_backports[ansible_distribution_release | lower] | length > 0 + ansible.builtin.copy: + dest: /etc/apt/preferences.d/90_zfs + mode: '0644' + owner: root + group: root + content: | + Package: src:zfs-linux + Pin: release n={{ ansible_distribution_release }}-backports + Pin-Priority: 990 + become: true + +- name: Handle CRB (Code Ready Builder) on RHEL-proper + when: ansible_distribution == 'RedHat' + community.general.rhsm_repository: + name: codeready-builder-for-rhel-{{ ansible_distribution_major_version }}-{{ ansible_architecture }}-rpms + state: enabled + become: true + +- name: Handle PowerTools (EL8) or CRB (EL9) on RHEL/Fedora derivatives + when: (ansible_os_family == 'RedHat') and (ansible_distribution not in ['RedHat', 'Fedora']) + community.general.dnf_config_manager: { name: "{{ 'powertools' if (ansible_distribution_major_version | int == 8) else 'crb' }}", state: enabled } + become: true + +- name: Kernel/Reboot tasks # skip potential disruption (reboot) if primary goal is achieved: ZFS loaded + when: (ansible_os_family == 'RedHat') and (zfs_dkms_dir.stat.islnk is not defined) + block: # Debian/Ubuntu are generous w/ kernel headers; EL/derivatives tend to host exactly three rotating kernels + - name: Ensure DNF/Yum utils (RHEL/Fedora+derivatives) + ansible.builtin.package: { name: yum-utils, state: present } + become: true + + - name: Check prior reboot necessity with 'needs-restarting' (RHEL/Fedora+derivatives) # reboot in case cloud-init/etc happened to update, ensures headers + ansible.builtin.command: needs-restarting -r + register: zfs_dkms_needs_restarting + changed_when: zfs_dkms_needs_restarting.rc > 0 + failed_when: zfs_dkms_needs_restarting.stderr_lines | length > 0 # skip rc check [non-zero indicates reboot requirement]; assume logs are legitimate + notify: zfs_dkms_reboot + become: true + + - name: Update Kernel (RHEL/Fedora+derivatives) # allows DKMS to build, headers for the kernel [in the image] are likely no longer mirrored + notify: zfs_dkms_reboot + ansible.builtin.package: { name: kernel-core, state: latest, update_cache: true, update_only: true } # 'update_only' for lint, surely already installed + become: true + +- name: Flush Handlers + ansible.builtin.meta: flush_handlers + +- name: Packages (build prep, [package-provided] repos) + ansible.builtin.package: + name: "{{ zfs_dkms_pkgs.pre[ansible_distribution | lower] }}" + state: present + update_cache: "{{ true if ansible_os_family in ['Debian', 'RedHat'] }}" # supported by Apt/DNF modules + cache_valid_time: "{{ 3600 if ansible_os_family == 'Debian' else omit }}" # idempotence/speed, Apt-specific + disable_gpg_check: "{{ true if ansible_os_family == 'RedHat' else omit }}" # signature+repo is installed from URL [with SSL/TLS] + become: true + +- name: Remove conflicting 'zfs-fuse' # most likely to appear w/ Fedora, requirement satisfied by real ZFS; placed before immediately install + ansible.builtin.command: rpm -e --nodeps zfs-fuse # noqa: command-instead-of-module (lack coverage) + when: "'zfs-fuse' in ansible_facts.packages" + changed_when: true # lint: assume on return, 'when' checks requirement + become: true + +- name: Packages (main) + ansible.builtin.package: { name: "{{ zfs_dkms_pkgs.main[ansible_distribution | lower] }}", state: present } + become: true + +- name: Protect ZFS/Kernel (Fedora) + ansible.builtin.copy: { dest: /etc/dnf/protected.d/zfs.conf, content: 'zfs', owner: root, group: root, mode: '0644' } + when: ansible_distribution == 'Fedora' + become: true + +- name: Load/persist Module, ensure ARC limits + community.general.modprobe: { name: zfs, persistent: present, params: "zfs_arc_min={{ zfs_dkms_arc['min'] }} zfs_arc_max={{ zfs_dkms_arc['max'] }}" } + become: true diff --git a/vars/main.yml b/vars/main.yml new file mode 100644 index 0000000..97c72e4 --- /dev/null +++ b/vars/main.yml @@ -0,0 +1,45 @@ +--- +# vars file for zfs_dkms + +zfs_dkms_arc: + min: "{{ (ansible_memory_mb['real']['total'] * zfs_dkms_arc_pct_min / 100 * 1024 * 1024) | round | int }}" + max: "{{ (ansible_memory_mb['real']['total'] * zfs_dkms_arc_pct_max / 100 * 1024 * 1024) | round | int }}" + +zfs_dkms_deb_backports: # ensure consistency between Debian releases. source(s) not required on Ubuntu, provided by 'universe' + bookworm: # '...backports-sloppy' would get Debian testing ('forky'), instead: want Trixie backports [to 12.x] + - "deb http://deb.debian.org/debian bookworm-backports main contrib" + - "deb-src http://deb.debian.org/debian bookworm-backports main contrib" + +zfs_dkms_pkgs: + pre: # (ansible_distribution | lower); packages wanted *before* trying to build ZFS + debian: + - dpkg-dev + - linux-headers-{{ ansible_kernel }} + ubuntu: [] + elcommon: &elcommonpre + - kernel-headers + - kernel-devel + - kernel-devel-matched + - epel-release + - "https://zfsonlinux.org/epel/zfs-release-2-8.el{{ ansible_distribution_major_version }}.noarch.rpm" + fedora: + - kernel-headers + - kernel-devel + - kernel-devel-matched + - "https://zfsonlinux.org/fedora/zfs-release-2-8.fc{{ ansible_distribution_major_version }}.noarch.rpm" + almalinux: *elcommonpre + rocky: *elcommonpre + redhat: + - https://dl.fedoraproject.org/pub/epel/epel-release-latest-{{ ansible_distribution_major_version }}.noarch.rpm + main: # the star of the show: ZFS transaction + debian: + - zfs-dkms + - zfsutils-linux + ubuntu: + - zfsutils-linux + elcommon: &elcommonmain + - zfs + fedora: *elcommonmain + almalinux: *elcommonmain + rocky: *elcommonmain + redhat: *elcommonmain