From 9466bdaecf11e17baafc3567431b5280dd3b1eb8 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Sat, 29 Mar 2025 22:26:49 +1100 Subject: [PATCH] feat: add zfs modules - add zfs_core module to puppetfile (provides zfs/zpool provider) - add module to manage zfs --- Puppetfile | 1 + .../zfs/lib/facter/zfs_zpool_cache_present.rb | 14 ++ modules/zfs/manifests/config.pp | 10 ++ modules/zfs/manifests/init.pp | 52 ++++++ modules/zfs/manifests/install.pp | 151 ++++++++++++++++++ modules/zfs/manifests/service.pp | 90 +++++++++++ 6 files changed, 318 insertions(+) create mode 100644 modules/zfs/lib/facter/zfs_zpool_cache_present.rb create mode 100644 modules/zfs/manifests/config.pp create mode 100644 modules/zfs/manifests/init.pp create mode 100644 modules/zfs/manifests/install.pp create mode 100644 modules/zfs/manifests/service.pp diff --git a/Puppetfile b/Puppetfile index 65c883d..7532e88 100644 --- a/Puppetfile +++ b/Puppetfile @@ -19,6 +19,7 @@ mod 'puppetlabs-haproxy', '8.0.0' mod 'puppetlabs-java', '10.1.2' mod 'puppetlabs-reboot', '5.0.0' mod 'puppetlabs-docker', '10.0.1' +mod 'puppetlabs-zfs_core', '1.6.1' # puppet mod 'puppet-python', '7.0.0' diff --git a/modules/zfs/lib/facter/zfs_zpool_cache_present.rb b/modules/zfs/lib/facter/zfs_zpool_cache_present.rb new file mode 100644 index 0000000..d2e87fe --- /dev/null +++ b/modules/zfs/lib/facter/zfs_zpool_cache_present.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +Facter.add('zfs_zpool_cache_present') do + confine kernel: 'Linux' + setcode do + File.exist?('/etc/zfs/zpool.cache') + end +end + +Facter.add('zfs_zpool_cache_present') do + setcode do + false + end +end diff --git a/modules/zfs/manifests/config.pp b/modules/zfs/manifests/config.pp new file mode 100644 index 0000000..b1e05fa --- /dev/null +++ b/modules/zfs/manifests/config.pp @@ -0,0 +1,10 @@ +# manage zfs config +class zfs::config { + + file { $zfs::conf_dir: + ensure => directory, + owner => 0, + group => 0, + mode => '0644', + } +} diff --git a/modules/zfs/manifests/init.pp b/modules/zfs/manifests/init.pp new file mode 100644 index 0000000..6feeeed --- /dev/null +++ b/modules/zfs/manifests/init.pp @@ -0,0 +1,52 @@ +# Installs basic ZFS kernel and userland support. +# +# @example Declaring the class +# include zfs +# +# @example Tuning the ZFS ARC +# class { 'zfs': +# zfs_arc_max => to_bytes('256 M'), +# zfs_arc_min => to_bytes('128 M'), +# } +# +# @param conf_dir Top-level configuration directory, usually `/etc/zfs`. +# @param kmod_type Whether to use DKMS kernel packages or ones built to match +# the running kernel (only applies to RHEL platforms). +# @param manage_repo Whether to setup and manage external package repositories. +# @param package_name The name of the top-level metapackage that installs ZFS +# support. +# @param service_manage Whether to manage the various ZFS services. +# @param zfs_arc_max Maximum size of the ARC in bytes. +# @param zfs_arc_min Minimum size of the ARC in bytes. +class zfs ( + Optional[Integer[0]] $zfs_arc_max, + Optional[Integer[0]] $zfs_arc_min, + Optional[Hash] $zpools, + Optional[Hash] $datasets, + Stdlib::Absolutepath $conf_dir = '/etc/zfs', + Enum['dkms', 'kabi'] $kmod_type = 'kabi', + Boolean $manage_repo = true, + Variant[String, Array[String, 1]] $package_name = 'zfs', + Boolean $service_manage = true, +) { + + contain zfs::install + contain zfs::config + contain zfs::service + + Class['zfs::install'] ~> Class['zfs::config'] ~> Class['zfs::service'] + + # create zpools + $zpools.each | $zpool, $data | { + zpool { $zpool: + * => $data + } + } + + # create datasets + $datasets.each | $dataset, $data | { + zfs { $dataset: + * => $data + } + } +} diff --git a/modules/zfs/manifests/install.pp b/modules/zfs/manifests/install.pp new file mode 100644 index 0000000..cb78576 --- /dev/null +++ b/modules/zfs/manifests/install.pp @@ -0,0 +1,151 @@ +# manage zfs install/repos +class zfs::install { + + if $zfs::manage_repo { + case $facts['os']['family'] { + 'RedHat': { + $baseurl = 'http://download.zfsonlinux.org' + $release = $facts['os']['release']['major'] ? { + '6' => '6', + '7' => $facts['os']['release']['full'] ? { + /^7\.[012]/ => '7', + default => regsubst($facts['os']['release']['full'], '^7\.(\d+).*$', '7.\1'), + }, + '8' => $facts['os']['release']['full'] ? { + /^8\.4/ => '8.3', + default => regsubst($facts['os']['release']['full'], '^8\.(\d+).*$', '8.\1'), + }, + default => regsubst($facts['os']['release']['full'], '^(\d\.\d+).*$', '\1'), + } + + yumrepo { 'zfs': + baseurl => "${baseurl}/epel/${release}/\$basearch/", + descr => "ZFS on Linux for EL${facts['os']['release']['major']} - dkms", + enabled => Integer($zfs::kmod_type == 'dkms'), + before => Package[$zfs::package_name], + } + + yumrepo { 'zfs-kmod': + baseurl => "${baseurl}/epel/${release}/kmod/\$basearch/", + descr => "ZFS on Linux for EL${facts['os']['release']['major']} - kmod", + enabled => Integer($zfs::kmod_type == 'kabi'), + } + + yumrepo { 'zfs-source': + baseurl => "${baseurl}/epel/${release}/SRPMS/", + descr => "ZFS on Linux for EL${facts['os']['release']['major']} - Source", + enabled => 0, + } + + yumrepo { 'zfs-testing': + baseurl => "${baseurl}/epel-testing/${release}/\$basearch/", + descr => "ZFS on Linux for EL${facts['os']['release']['major']} - dkms - Testing", + enabled => 0, + } + + yumrepo { 'zfs-testing-kmod': + baseurl => "${baseurl}/epel-testing/${release}/kmod/\$basearch/", + descr => "ZFS on Linux for EL${facts['os']['release']['major']} - kmod - Testing", + enabled => 0, + } + + yumrepo { 'zfs-testing-source': + baseurl => "${baseurl}/epel-testing/${release}/SRPMS/", + descr => "ZFS on Linux for EL${facts['os']['release']['major']} - Testing Source", + enabled => 0, + } + } + default: { + # noop + } + } + } + + # Handle these dependencies separately as they shouldn't be guarded by + # `$zfs::manage_repo` + case $facts['os']['family'] { + 'RedHat': { + case $zfs::kmod_type { + 'dkms': { + # Puppet doesn't like managing multiple versions of the same package. + # By using the version in the name Yum will do the right thing + ensure_packages(["kernel-devel-${facts['kernelrelease']}"], { + ensure => present, + before => Package[$zfs::package_name], + }) + } + default: { + # noop + } + } + } + 'Debian': { + case $facts['os']['name'] { + 'Ubuntu': { + # noop + } + default: { + ensure_packages(["linux-headers-${facts['kernelrelease']}", "linux-headers-${facts['os']['architecture']}"], { + before => Package[$zfs::package_name], + }) + } + } + } + default: { + # noop + } + } + + # This is to work around the broken Debian 9 packages. Upon install the + # zfs-mount.service is started first which is the only unit that doesn't + # have an "ExecStartPre=-/sbin/modprobe zfs" line so the package can never + # be installed! + if $facts['os']['name'] == 'Debian' and $facts['os']['release']['major'] == '9' { + exec { 'zfs systemctl daemon-reload': + command => 'systemctl daemon-reload', + refreshonly => true, + path => $facts['path'], + } + + Exec['zfs systemctl daemon-reload'] -> Package[$zfs::package_name] + + file { '/etc/systemd/system/zfs-mount.service.d': + ensure => directory, + owner => 0, + group => 0, + mode => '0644', + } + + file { '/etc/systemd/system/zfs-mount.service.d/override.conf': + ensure => file, + owner => 0, + group => 0, + mode => '0644', + content => @(EOS/L), + [Service] + ExecStartPre=-/sbin/modprobe zfs + | EOS + notify => Exec['zfs systemctl daemon-reload'], + } + } + + # These need to be done here so the kernel settings are present before the + # package is installed and potentially loading the kernel module + $config = delete_undef_values({ + 'zfs_arc_max' => $zfs::zfs_arc_max, + 'zfs_arc_min' => $zfs::zfs_arc_min, + }) + + $config.each |$option,$value| { + kmod::option { "zfs ${option}": + module => 'zfs', + option => $option, + value => $value, + before => Package[$zfs::package_name], + } + } + + package { $zfs::package_name: + ensure => present, + } +} diff --git a/modules/zfs/manifests/service.pp b/modules/zfs/manifests/service.pp new file mode 100644 index 0000000..64ec056 --- /dev/null +++ b/modules/zfs/manifests/service.pp @@ -0,0 +1,90 @@ +# manage zfs services +class zfs::service { + + if $zfs::service_manage { + + exec { 'modprobe zfs': + path => $facts['path'], + unless => 'grep -q "^zfs " /proc/modules', + } + + case $facts['service_provider'] { + 'systemd': { + $cache_ensure = str2bool($facts['zfs_zpool_cache_present']) ? { + true => 'running', + default => 'stopped', + } + + $scan_ensure = str2bool($facts['zfs_zpool_cache_present']) ? { + true => 'stopped', + default => 'running', + } + + service { 'zfs-import-cache': + ensure => $cache_ensure, + enable => true, + hasstatus => true, + hasrestart => true, + require => Exec['modprobe zfs'], + before => Service['zfs-mount'], + } + + service { 'zfs-import-scan': + ensure => $scan_ensure, + enable => true, + hasstatus => true, + hasrestart => true, + require => Exec['modprobe zfs'], + before => Service['zfs-mount'], + } + } + default: { + + case $facts['os']['family'] { + 'RedHat': { + service { 'zfs-import': + ensure => running, + enable => true, + hasstatus => true, + hasrestart => true, + require => Exec['modprobe zfs'], + before => Service['zfs-mount'], + } + } + 'Debian': { + $import_ensure = str2bool($facts['zfs_zpool_cache_present']) ? { + true => 'running', + default => 'stopped', + } + + service { 'zpool-import': + ensure => $import_ensure, + enable => true, + hasstatus => true, + hasrestart => true, + require => Exec['modprobe zfs'], + } + } + default: { + # noop + } + } + } + } + + service { 'zfs-mount': + ensure => running, + enable => true, + hasstatus => true, + hasrestart => true, + before => Service['zfs-share'], + } + + service { 'zfs-share': + ensure => running, + enable => true, + hasstatus => true, + hasrestart => true, + } + } +} -- 2.47.3