diff --git a/data/common/common.yaml b/data/common/common.yaml --- a/data/common/common.yaml +++ b/data/common/common.yaml @@ -3700,3 +3700,6 @@ hourly_crit: 3600 daily_warn: 48 daily_crit: 60 + +syncoid::configuration: {} +syncoid::default_delay: 5min diff --git a/site-modules/profile/manifests/sanoid/configure_sync_source.pp b/site-modules/profile/manifests/sanoid/configure_sync_source.pp new file mode 100644 --- /dev/null +++ b/site-modules/profile/manifests/sanoid/configure_sync_source.pp @@ -0,0 +1,16 @@ +define profile::sanoid::configure_sync_source( + String $user, + String $ssh_key_name, + String $ssh_key_type, + String $authorized_key, +) { + + include profile::sanoid::install + + ensure_resource('ssh_authorized_key', $ssh_key_name, { + ensure => 'present', + user => $user, + type => $ssh_key_type, + key => $authorized_key, + }) +} diff --git a/site-modules/profile/manifests/sanoid/install.pp b/site-modules/profile/manifests/sanoid/install.pp new file mode 100644 --- /dev/null +++ b/site-modules/profile/manifests/sanoid/install.pp @@ -0,0 +1,75 @@ +class profile::sanoid::install { + + if versioncmp($::lsbmajdistrelease, '11') >= 0 { + # Install the official package + ensure_packages('sanoid') + } else { + # Buster and below, install a github release archive + + $version = '2.0.3' + $archive_digest = '63115326695a00dc925d3ec8c307ed2543bb0a2479f2b15be3192bf2c7d50037' + $archive_digest_type = 'sha256' + + $archive_url = "https://github.com/jimsalterjrs/sanoid/archive/refs/tags/v${version}.tar.gz" + $archive_path = "/opt/sanoid-v${version}.tar.gz" + $install_path = "/opt/sanoid-${version}" + + ensure_packages([ + 'libcapture-tiny-perl', + 'libconfig-inifiles-perl', + 'zfsutils-linux', + 'lzop', + 'mbuffer', + 'pv', + ]) + + file { $install_path : + ensure => directory, + owner => 'root', + group => 'root', + } + + archive { 'sanoid': + path => $archive_path, + extract => true, + extract_command => 'tar xzf %s --strip-components=1 --no-same-owner --no-same-permissions', + source => $archive_url, + extract_path => $install_path, + checksum => $archive_digest, + checksum_type => $archive_digest_type, + creates => "${install_path}/sanoid", + cleanup => true, + user => 'root', + group => 'root', + require => File[$install_path], + } + file { '/opt/sanoid' : + ensure => link, + target => $install_path, + owner => 'root', + group => 'root', + require => Archive['sanoid'], + } + file { '/usr/sbin/sanoid' : + ensure => link, + target => '/opt/sanoid/sanoid', + owner => 'root', + group => 'root', + } + file { '/usr/sbin/syncoid' : + ensure => link, + target => '/opt/sanoid/syncoid', + owner => 'root', + group => 'root', + } + file { '/usr/sbin/findoid' : + ensure => link, + target => '/opt/sanoid/findoid', + owner => 'root', + group => 'root', + } + + + } + +} diff --git a/site-modules/profile/manifests/sanoid/backup.pp b/site-modules/profile/manifests/sanoid/snapshot.pp rename from site-modules/profile/manifests/sanoid/backup.pp rename to site-modules/profile/manifests/sanoid/snapshot.pp --- a/site-modules/profile/manifests/sanoid/backup.pp +++ b/site-modules/profile/manifests/sanoid/snapshot.pp @@ -1,5 +1,7 @@ -class profile::sanoid::backup { - ensure_packages('sanoid') +# Configure recurrent zfs snapshot +# using sanoid +class profile::sanoid::snapshot { + include profile::sanoid::install $config_dir = '/etc/sanoid' $config_file = "${config_dir}/sanoid.conf" diff --git a/site-modules/profile/manifests/sanoid/sync_destination.pp b/site-modules/profile/manifests/sanoid/sync_destination.pp new file mode 100644 --- /dev/null +++ b/site-modules/profile/manifests/sanoid/sync_destination.pp @@ -0,0 +1,67 @@ +# Configure a server to be the destination +# of a zfs snapshot synchronization +# This server will pull the snasphots from +# the sources +class profile::sanoid::sync_destination { + + $configuration = lookup('syncoid::configuration') + + $sources = $configuration["sources"] + + if $sources { + include profile::sanoid::install + + $sources.each | $key, $config | { + $source_host = $config['host'] + + $ssh_key_name = $config['ssh_key'] + $ssh_key = lookup("syncoid::ssh_key::${ssh_key_name}") + $authorized_key = lookup("syncoid::public_keys::${ssh_key_name}") + $ssh_key_type = $authorized_key["type"] + # computing a substring of ssh_key_type to remove 'ssh-' of the name + $ssh_key_filename = "/root/.ssh/id_${ssh_key_type[4,255]}.syncoid_${ssh_key_name}" + + ensure_resource( 'file', $ssh_key_filename, { + ensure => present, + owner => 'root', + group => 'root', + mode => '0600', + content => $ssh_key, + }) + + @@::profile::sanoid::configure_sync_source { $::fqdn: + user => 'root', + ssh_key_name => "syncoid_${ssh_key_name}", + ssh_key_type => $ssh_key_type, + authorized_key => $authorized_key['key'], + tag => $source_host, + } + + # Create a timer and service for each dataset to sync + $config['datasets'].each | $name, $props | { + $dataset = $props['dataset'] + $destination = "${config['target_dataset_base']}/${key}/${name}" + $service_basename = "syncoid-${key}-${name}" + $source = "${source_host}:${dataset}" + $delay = pick($props['delay'], lookup('syncoid::default_delay')) + + # templates use: + # - $ssh_key_filename + # - $source + # - $destination + # - $delay + # - $service_basename + ::systemd::timer { "${service_basename}.timer": + timer_content => template('profile/sanoid/syncoid.timer.erb'), + service_content => template('profile/sanoid/syncoid.service.erb'), + service_unit => "${service_basename}.service", + active => true, + enable => true, + } + + } + } + } + + +} diff --git a/site-modules/profile/manifests/sanoid/sync_source.pp b/site-modules/profile/manifests/sanoid/sync_source.pp new file mode 100644 --- /dev/null +++ b/site-modules/profile/manifests/sanoid/sync_source.pp @@ -0,0 +1,10 @@ +# Configure a server to be a source +# of a zfs snapshot synchronization +# mostly configure the ssh key to allow +# the destination server to pull the +# dataset +class profile::sanoid::sync_source { + + ::Profile::Sanoid::Configure_sync_source <<| tag == "${::fqdn}" |>> + +} diff --git a/site-modules/profile/templates/sanoid/sanoid.conf.erb b/site-modules/profile/templates/sanoid/sanoid.conf.erb --- a/site-modules/profile/templates/sanoid/sanoid.conf.erb +++ b/site-modules/profile/templates/sanoid/sanoid.conf.erb @@ -1,4 +1,4 @@ -# File managed with puppet (module profile::sanoid::backup) +# File managed with puppet (module profile::sanoid::snapshot) # All modifications will be lost <%- @dataset_configuration.each do |dataset, config| -%> diff --git a/site-modules/profile/templates/sanoid/syncoid.service.erb b/site-modules/profile/templates/sanoid/syncoid.service.erb new file mode 100644 --- /dev/null +++ b/site-modules/profile/templates/sanoid/syncoid.service.erb @@ -0,0 +1,14 @@ +# Managed by puppet class profile::sanoid::syncoid_destination +# Changes will be overwritten + +[Unit] +Description=ZFS dataset synchronization of <% @source %> + +[Service] +Type=oneshot +User=root +Group=root +ExecStart=syncoid --sshkey <%= @ssh_key_filename %> root@<%= @source %> <%= @destination %> + +[Install] +WantedBy=multi-user.target diff --git a/site-modules/profile/templates/sanoid/syncoid.timer.erb b/site-modules/profile/templates/sanoid/syncoid.timer.erb new file mode 100644 --- /dev/null +++ b/site-modules/profile/templates/sanoid/syncoid.timer.erb @@ -0,0 +1,14 @@ +# Managed by puppet class profile::sanoid::syncoid_destination +# Changes will be overwritten +[Unit] +Description=ZFS dataset synchronization trigger + +[Install] +WantedBy=timers.target + +[Timer] +OnBootSec=1m +OnUnitActiveSec=<%= @delay %> +RandomizedDelaySec=1min +FixedRandomDelay=true +Unit=<%= @service_basename %>.service diff --git a/site-modules/role/manifests/swh_admin_database.pp b/site-modules/role/manifests/swh_admin_database.pp --- a/site-modules/role/manifests/swh_admin_database.pp +++ b/site-modules/role/manifests/swh_admin_database.pp @@ -2,5 +2,5 @@ include profile::postgresql include profile::postgresql::server include profile::prometheus::sql - include profile::sanoid::backup + include profile::sanoid::snapshot } diff --git a/site-modules/role/manifests/swh_base.pp b/site-modules/role/manifests/swh_base.pp --- a/site-modules/role/manifests/swh_base.pp +++ b/site-modules/role/manifests/swh_base.pp @@ -20,4 +20,7 @@ include profile::smartmontools include profile::network include profile::swh + + include profile::sanoid::sync_source + include profile::sanoid::sync_destination }