From 46e5fc084a8e3238d538299c0962012f59e42a14 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 8 Feb 2024 16:22:39 +0000 Subject: [PATCH 1/6] Introduce dst_N_autocreation toggles via ZFS properties Note lower-case "c" in autoCreation - dictated by ZFS property name constraints Signed-off-by: Jim Klimov --- CHANGES | 1 + bin/znapzend | 3 +++ lib/ZnapZend.pm | 58 ++++++++++++++++++++++++++++++++++++------ lib/ZnapZend/Config.pm | 22 ++++++++++++++-- 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 368f9198..11a4cd84 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,7 @@ znapzend (0.21.3) unstable; urgency=medium * Fixed CI recipes and contents for spell-checker * Added rc-script and integration documentation for FreeBSD and similar platforms * Extended `--autoCreation` effect (or lack thereof) to newly appearing sub-datasets; added a `--noautoCreation` option to help override configuration file settings (where used) + * Introduced `dst_N_autocreation` setting via ZFS properties (per-destination, inheritable) -- Jim Klimov Tue, 9 Jan 2024 13:42:28 +0100 diff --git a/bin/znapzend b/bin/znapzend index d8efbe3f..e4492985 100755 --- a/bin/znapzend +++ b/bin/znapzend @@ -85,6 +85,9 @@ sub main { $opts->{forbidDestRollback} = 0; } + # Note: default is "undef" to use a ZFS property dst_N_autocreation + # (lower-case "c" in the name) if present; finally assumes 0 (false) + # if not set in any configuration source for a particular dataset. if (defined($opts->{noautoCreation})) { $opts->{autoCreation} = 0; delete $opts->{noautoCreation}; diff --git a/lib/ZnapZend.pm b/lib/ZnapZend.pm index 75581566..53868698 100644 --- a/lib/ZnapZend.pm +++ b/lib/ZnapZend.pm @@ -49,7 +49,7 @@ has pidfile => sub { q{} }; has forcedSnapshotSuffix => sub { q{} }; has defaultPidFile => sub { q{/var/run/znapzend.pid} }; has terminate => sub { 0 }; -has autoCreation => sub { 0 }; +has autoCreation => sub { undef }; has timeWarp => sub { undef }; has nodelay => sub { 0 }; has skipOnPreSnapCmdFail => sub { 0 }; @@ -247,6 +247,15 @@ my $refreshBackupPlans = sub { #create backup hashes for all destinations for (keys %$backupSet){ my ($key) = /^dst_([^_]+)_plan$/ or next; + my $autoCreation = $self->autoCreation; + if (!defined($autoCreation)) { + # Caller did not require any particular behavior, so + # check the ZFS property name (note lower-case "c"): + $autoCreation = (exists $backupSet->{"dst_$key" . '_autocreation'} ? $backupSet->{"dst_$key" . '_autocreation'} : undef); + } + if (!defined($autoCreation)) { + $autoCreation = 0; + } #check if destination exists (i.e. is valid) otherwise recheck as dst might be online, now if (!$backupSet->{"dst_$key" . '_valid'}){ @@ -254,7 +263,7 @@ my $refreshBackupPlans = sub { $backupSet->{"dst_$key" . '_valid'} = $self->zZfs->dataSetExists($backupSet->{"dst_$key"}) or do { - if ($self->autoCreation && !$self->sendRaw) { + if ($autoCreation && !$self->sendRaw) { my ($zpool) = $backupSet->{"dst_$key"} =~ /(^[^\/]+)\//; # check if we can access destination zpool, if so create parent dataset @@ -272,7 +281,7 @@ my $refreshBackupPlans = sub { $backupSet->{"dst_$key" . '_valid'} or $self->zLog->warn("destination '" . $backupSet->{"dst_$key"} . "' does not exist or is offline. will be rechecked every run..." - . ( $self->autoCreation ? "" : " Consider running znapzend --autoCreation" ) ); + . ( $autoCreation ? "" : " Consider running znapzend --autoCreation" ) ); }; $self->zLog->debug('refreshBackupPlans(): detected dst_' . $key . '_valid status for ' . $backupSet->{"dst_$key"} . ': ' . $backupSet->{"dst_$key" . '_valid'}) if ($self->debug); @@ -406,10 +415,23 @@ my $sendRecvCleanup = sub { #recheck non valid dst as it might be online, now if (!$backupSet->{"dst_$key" . '_valid'}) { + my $autoCreation = $self->autoCreation; + if (!defined($autoCreation)) { + # Caller did not require any particular behavior, so + # check the ZFS property name (note lower-case "c"). + # Note we are looking at "root" datasets with a backup + # schedule here (enumerated earlier); children if any + # would be checked below: + $autoCreation = (exists $backupSet->{"dst_$key" . '_autocreation'} ? $backupSet->{"dst_$key" . '_autocreation'} : undef); + } + if (!defined($autoCreation)) { + $autoCreation = 0; + } + $backupSet->{"dst_$key" . '_valid'} = $self->zZfs->dataSetExists($backupSet->{"dst_$key"}) or do { - if ($self->autoCreation && !$self->sendRaw) { + if ($autoCreation && !$self->sendRaw) { my ($zpool) = $backupSet->{"dst_$key"} =~ /(^[^\/]+)\//; # check if we can access destination zpool, if so - @@ -427,7 +449,7 @@ my $sendRecvCleanup = sub { } }; } - ( $backupSet->{"dst_$key" . '_valid'} || ($self->sendRaw && $self->autoCreation) ) or do { + ( $backupSet->{"dst_$key" . '_valid'} || ($self->sendRaw && $autoCreation) ) or do { my $errmsg = "destination '" . $backupSet->{"dst_$key"} . "' does not exist or is offline; ignoring it for this round..."; $self->zLog->warn($errmsg); @@ -450,14 +472,34 @@ my $sendRecvCleanup = sub { my $dstDataSet = $srcDataSet; $dstDataSet =~ s/^\Q$backupSet->{src}\E/$backupSet->{$dst}/; + my $autoCreation = $self->autoCreation; + if (!defined($autoCreation)) { + # Caller did not require any particular behavior, so + # check the ZFS property name (note lower-case "c"). + # Look at properties of this dataset, allow inherited + # values. TOTHINK: Get properties once for all tree? + my $properties = $self->zZfs->getDataSetProperties($srcDataSet, 0, 1); + if ($properties->[0]) { + for my $prop (keys %{$properties->[0]}) { + if ($prop eq "dst_$key" . '_autocreation') { + $autoCreation = (%{$properties->[0]}{$prop} eq "on" ? 1 : 0); + last; + } + } + } + } + if (!defined($autoCreation)) { + $autoCreation = 0; + } + $self->zLog->debug('sending snapshots from ' . $srcDataSet . ' to ' . $dstDataSet . ((grep (/^\Q$srcDataSet\E$/, @dataSetsExplicitlyDisabled)) ? ": not enabled, should be skipped" : "")); # Time to check if the target sub-dataset exists # at all (unless we would auto-create one anyway). - if (!$self->autoCreation && !$self->sendRaw && !$self->zZfs->dataSetExists($dstDataSet)) { + if (!$autoCreation && !$self->sendRaw && !$self->zZfs->dataSetExists($dstDataSet)) { my $errmsg = "sub-destination '" . $dstDataSet . "' does not exist or is offline; ignoring it for this round... Consider " - . ( $self->autoCreation || $self->sendRaw ? "" : "running znapzend --autoCreation or " ) + . ( $autoCreation || $self->sendRaw ? "" : "running znapzend --autoCreation or " ) . "disabling this dataset from znapzend handling."; $self->zLog->warn($errmsg); push (@sendFailed, $errmsg); @@ -473,7 +515,7 @@ my $sendRecvCleanup = sub { 'since=="' . $self->since . '"'. ', skipIntermediates=="' . $self->skipIntermediates . '"' . ', forbidDestRollback=="' . $self->forbidDestRollback . '"' . - ', autoCreation=="' . $self->autoCreation . '"' . + ', autoCreation=="' . ( $autoCreation ? "true" : "false" ) . '"' . ', sendRaw=="' . $self->sendRaw . '"' . ', valid=="' . ( $backupSet->{"dst_$key" . '_valid'} ? "true" : "false" ) . '"' . ', justCreated=="' . ( $backupSet->{"dst_$key" . '_justCreated'} ? "true" : "false" ) . '"' diff --git a/lib/ZnapZend/Config.pm b/lib/ZnapZend/Config.pm index 53403441..14a5453f 100644 --- a/lib/ZnapZend/Config.pm +++ b/lib/ZnapZend/Config.pm @@ -86,6 +86,11 @@ my $checkBackupSets = sub { my $self = shift; for my $backupSet (@{$self->backupSets}){ + # Note that we only normally call this either when we walk all + # known backup/retention schedules (datasets with at least one + # local "org.znapzend:..." property), or just once for a single + # "--runonce=..." backupSet (not recursing into children with + # their exceptional settings then, unless also "--recursive"). # In case there is only one property on this dataset, which is the # "enabled" flag and is set to "off"; consider it a normal situation @@ -94,8 +99,21 @@ my $checkBackupSets = sub { # Note: backupSets will have at least the key "src". Therefore, we # need to skip the dataset if there are two properties and one of # them is "enabled". - if (keys(%{$backupSet}) eq 2 && exists($backupSet->{"enabled"})){ - next; + # Similarly, skip checking datasets (enabled or not) that have only + # an autoCreation setting for particular destination(s); note that + # ZFS property names must be lower-case (so "c" is small here). + my @backupSetKeysFiltered = grep (!/^dst_[^_]+_autocreation$/, keys(%{$backupSet})); + my $backupSetKeysFiltered = scalar(@backupSetKeysFiltered); + $self->zLog->debug("#checkBackupSets# backupSetKeysFiltered " + . "for '" . $backupSet->{src} . "' = (" + . $backupSetKeysFiltered . ")[" + . join(", ", @backupSetKeysFiltered) . "]" + ) if $self->debug; + + if ( ($backupSetKeysFiltered eq 2 and exists($backupSet->{"enabled"})) + or $backupSetKeysFiltered eq 1 + ) { + next; } if ( $backupSet->{src} =~ m/[\@]/ ) { From 570bd7aad984520e353372092eb43bd8b9ea74c2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 8 Feb 2024 21:06:47 +0000 Subject: [PATCH 2/6] znapzendzetup: support toggling or inheriting a dst_N_autocreation property Signed-off-by: Jim Klimov --- .github/workflows/spelling/expect.txt | 1 + bin/znapzendzetup | 54 ++++++++++ lib/ZnapZend/Config.pm | 136 ++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) diff --git a/.github/workflows/spelling/expect.txt b/.github/workflows/spelling/expect.txt index 0b934d3b..1f7f1190 100644 --- a/.github/workflows/spelling/expect.txt +++ b/.github/workflows/spelling/expect.txt @@ -26,6 +26,7 @@ attr austingroupbugs autocommit autoconf +autocreation autom automake automounting diff --git a/bin/znapzendzetup b/bin/znapzendzetup index 77d376df..4470c939 100755 --- a/bin/znapzendzetup +++ b/bin/znapzendzetup @@ -402,6 +402,54 @@ sub main { last; }; + /^enable-dst-autocreation$/ && do { + $opts->{dst} = pop @ARGV; + $opts->{src} = pop @ARGV; + if (!defined $opts->{src}) { + pod2usage(-exitval => 'NOEXIT'); + die ("ERROR: source argument for option $mainOpt was not provided\n"); + } + if (!defined $opts->{dst}) { + pod2usage(-exitval => 'NOEXIT'); + die ("ERROR: destination argument for option $mainOpt was not provided\n"); + } + $zConfig->enableBackupSetDstAutoCreation($opts->{src}, $opts->{dst}) + or die "ERROR: cannot enable backup config for $opts->{src} destination $opts->{dst}. Did you create this config?\n"; + + last; + }; + /^disable-dst-autocreation$/ && do { + $opts->{dst} = pop @ARGV; + $opts->{src} = pop @ARGV; + if (!defined $opts->{src}) { + pod2usage(-exitval => 'NOEXIT'); + die ("ERROR: source argument for option $mainOpt was not provided\n"); + } + if (!defined $opts->{dst}) { + pod2usage(-exitval => 'NOEXIT'); + die ("ERROR: destination argument for option $mainOpt was not provided\n"); + } + $zConfig->disableBackupSetDstAutoCreation($opts->{src}, $opts->{dst}) + or die "ERROR: cannot disable backup config for $opts->{src} destination $opts->{dst}. Did you create this config?\n"; + + last; + }; + /^inherit-dst-autocreation$/ && do { + $opts->{dst} = pop @ARGV; + $opts->{src} = pop @ARGV; + if (!defined $opts->{src}) { + pod2usage(-exitval => 'NOEXIT'); + die ("ERROR: source argument for option $mainOpt was not provided\n"); + } + if (!defined $opts->{dst}) { + pod2usage(-exitval => 'NOEXIT'); + die ("ERROR: destination argument for option $mainOpt was not provided\n"); + } + $zConfig->inheritBackupSetDstAutoCreation($opts->{src}, $opts->{dst}) + or die "ERROR: cannot disable backup config for $opts->{src} destination $opts->{dst}. Did you create this config?\n"; + + last; + }; /^list$/ && do { GetOptions($opts, (@ROOT_EXEC_OPTIONS, qw(recursive|r inherited))) or exit 1; @@ -591,6 +639,12 @@ and where 'command' and its unique options is one of the following: disable-dst + enable-dst-autocreation + + disable-dst-autocreation + + inherit-dst-autocreation + list [--recursive] [--inherited] [src_dataset...] export diff --git a/lib/ZnapZend/Config.pm b/lib/ZnapZend/Config.pm index 14a5453f..3735b1fd 100644 --- a/lib/ZnapZend/Config.pm +++ b/lib/ZnapZend/Config.pm @@ -520,6 +520,142 @@ sub disableBackupSetDst { return 0; } +sub enableBackupSetDstAutoCreation { + my $self = shift; + my $dataSet = shift; + my $dest = shift; + my $recurse = shift; # may be undef + my $inherit = shift; # may be undef + + $self->zfs->dataSetExists($dataSet) or die "ERROR: dataset $dataSet does not exist\n"; + + $self->backupSets($self->zfs->getDataSetProperties($dataSet, $recurse, $inherit)); + + if (@{$self->backupSets}){ + my %cfg = %{$self->backupSets->[0]}; + + if ( !($dest =~ /^dst_[^_]+$/) ) { + if ($cfg{'dst_' . $dest}) { + # User passed valid key of the destination config, + # convert to zfs attribute/perl struct name part + $dest = 'dst_' . $dest; + } elsif ($dest =~ /^DST:/) { + my $desttemp = $dest; + $desttemp =~ s/^DST:// ; + if ($cfg{'dst_' . $desttemp}) { + # User passed valid key of the destination config, + # convert to zfs attribute/perl struct name part + $dest = 'dst_' . $desttemp; + } + } + # TODO: Else search by value of 'dst_N' as a "(remote@)dataset" + } + + if ($cfg{$dest}) { + if ($cfg{$dest . '_autocreation'}) { + $cfg{$dest . '_autocreation'} = 'on'; + } + } else { + die "ERROR: dataset $dataSet backup plan does not have destination $dest\n"; + } + $self->setBackupSet(\%cfg); + + return 1; + } + + return 0; +} + +sub disableBackupSetDstAutoCreation { + my $self = shift; + my $dataSet = shift; + my $dest = shift; + my $recurse = shift; # may be undef + my $inherit = shift; # may be undef + + $self->zfs->dataSetExists($dataSet) or die "ERROR: dataset $dataSet does not exist\n"; + + $self->backupSets($self->zfs->getDataSetProperties($dataSet, $recurse, $inherit)); + + if (@{$self->backupSets}){ + my %cfg = %{$self->backupSets->[0]}; + + if ( !($dest =~ /^dst_[^_]+$/) ) { + if ($cfg{'dst_' . $dest}) { + # User passed valid key of the destination config, + # convert to zfs attribute/perl struct name part + $dest = 'dst_' . $dest; + } elsif ($dest =~ /^DST:/) { + my $desttemp = $dest; + $desttemp =~ s/^DST:// ; + if ($cfg{'dst_' . $desttemp}) { + # User passed valid key of the destination config, + # convert to zfs attribute/perl struct name part + $dest = 'dst_' . $desttemp; + } + } + # TODO: Else search by value of 'dst_N' as a "(remote@)dataset" + } + + if ($cfg{$dest}) { + $cfg{$dest . '_autocreation'} = 'off'; + } else { + die "ERROR: dataset $dataSet backup plan does not have destination $dest\n"; + } + $self->setBackupSet(\%cfg); + + return 1; + } + + return 0; +} + +sub inheritBackupSetDstAutoCreation { + my $self = shift; + my $dataSet = shift; + my $dest = shift; + my $recurse = shift; # may be undef + my $inherit = shift; # may be undef + + $self->zfs->dataSetExists($dataSet) or die "ERROR: dataset $dataSet does not exist\n"; + + $self->backupSets($self->zfs->getDataSetProperties($dataSet, $recurse, $inherit)); + + if (@{$self->backupSets}){ + my %cfg = %{$self->backupSets->[0]}; + + if ( !($dest =~ /^dst_[^_]+$/) ) { + if ($cfg{'dst_' . $dest}) { + # User passed valid key of the destination config, + # convert to zfs attribute/perl struct name part + $dest = 'dst_' . $dest; + } elsif ($dest =~ /^DST:/) { + my $desttemp = $dest; + $desttemp =~ s/^DST:// ; + if ($cfg{'dst_' . $desttemp}) { + # User passed valid key of the destination config, + # convert to zfs attribute/perl struct name part + $dest = 'dst_' . $desttemp; + } + } + # TODO: Else search by value of 'dst_N' as a "(remote@)dataset" + } + + if ($cfg{$dest}) { + if ($cfg{$dest . '_autocreation'}) { + $cfg{$dest . '_autocreation'} = undef; + } + } else { + die "ERROR: dataset $dataSet backup plan does not have destination $dest\n"; + } + $self->setBackupSet(\%cfg); + + return 1; + } + + return 0; +} + 1; __END__ From 2b5d5f2713370fb0fdcfb54b11af9e4c3a894902 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 19 Feb 2024 22:34:08 +0000 Subject: [PATCH 3/6] lib/ZnapZend.pm: do not fail the run if dataset was skipped because autocreation is disabled Signed-off-by: Jim Klimov --- lib/ZnapZend.pm | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/ZnapZend.pm b/lib/ZnapZend.pm index 53868698..cefb9833 100644 --- a/lib/ZnapZend.pm +++ b/lib/ZnapZend.pm @@ -453,8 +453,12 @@ my $sendRecvCleanup = sub { my $errmsg = "destination '" . $backupSet->{"dst_$key"} . "' does not exist or is offline; ignoring it for this round..."; $self->zLog->warn($errmsg); - push (@sendFailed, $errmsg); - $thisSendFailed = 1; + if (!$autoCreation) { + $self->zLog->warn("Autocreation is disabled for this dataset or whole run, so skipping without error"); + } else { + push (@sendFailed, $errmsg); + $thisSendFailed = 1; + } next; }; }; @@ -496,14 +500,18 @@ my $sendRecvCleanup = sub { # Time to check if the target sub-dataset exists # at all (unless we would auto-create one anyway). - if (!$autoCreation && !$self->sendRaw && !$self->zZfs->dataSetExists($dstDataSet)) { + if ((!$autoCreation || !$self->sendRaw) && !($self->zZfs->dataSetExists($dstDataSet))) { my $errmsg = "sub-destination '" . $dstDataSet . "' does not exist or is offline; ignoring it for this round... Consider " . ( $autoCreation || $self->sendRaw ? "" : "running znapzend --autoCreation or " ) . "disabling this dataset from znapzend handling."; $self->zLog->warn($errmsg); - push (@sendFailed, $errmsg); - $thisSendFailed = 1; + if (!$autoCreation) { + $self->zLog->warn("Autocreation is disabled for this dataset or whole run, so skipping without error"); + } else { + push (@sendFailed, $errmsg); + $thisSendFailed = 1; + } next; } From 4e45c1e8123725a383b0371bd28c45a08798a0c4 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 21 Feb 2024 15:32:53 +0100 Subject: [PATCH 4/6] Update expect.txt --- .github/workflows/spelling/expect.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/spelling/expect.txt b/.github/workflows/spelling/expect.txt index 1f7f1190..4deb58e9 100644 --- a/.github/workflows/spelling/expect.txt +++ b/.github/workflows/spelling/expect.txt @@ -72,6 +72,7 @@ Bznapzendzetup Bznapzendztatz canmount CBuilder +cdn cfg cgi cgit From cf0e4b11aefb18ebbf0745951bda5d0555d1a743 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 10 Mar 2024 22:31:03 +0000 Subject: [PATCH 5/6] lib/ZnapZend.pm: Avoid spamming for every loop cycle, if we do not have the dataset and know we do not intend to auto-create it Signed-off-by: Jim Klimov --- lib/ZnapZend.pm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/ZnapZend.pm b/lib/ZnapZend.pm index cefb9833..5b836366 100644 --- a/lib/ZnapZend.pm +++ b/lib/ZnapZend.pm @@ -452,9 +452,11 @@ my $sendRecvCleanup = sub { ( $backupSet->{"dst_$key" . '_valid'} || ($self->sendRaw && $autoCreation) ) or do { my $errmsg = "destination '" . $backupSet->{"dst_$key"} . "' does not exist or is offline; ignoring it for this round..."; - $self->zLog->warn($errmsg); + # Avoid spamming for every loop cycle, if we do not have + # the dataset and know we do not intend to auto-create it + $self->zLog->warn($errmsg) if ($autoCreation or $self->debug); if (!$autoCreation) { - $self->zLog->warn("Autocreation is disabled for this dataset or whole run, so skipping without error"); + $self->zLog->warn("Autocreation is disabled for this dataset or whole run, so skipping without error") if ($self->debug); } else { push (@sendFailed, $errmsg); $thisSendFailed = 1; @@ -505,9 +507,11 @@ my $sendRecvCleanup = sub { . "' does not exist or is offline; ignoring it for this round... Consider " . ( $autoCreation || $self->sendRaw ? "" : "running znapzend --autoCreation or " ) . "disabling this dataset from znapzend handling."; - $self->zLog->warn($errmsg); + # Avoid spamming for every loop cycle, if we do not have + # the dataset and know we do not intend to auto-create it + $self->zLog->warn($errmsg) if ($autoCreation or $self->debug); if (!$autoCreation) { - $self->zLog->warn("Autocreation is disabled for this dataset or whole run, so skipping without error"); + $self->zLog->warn("Autocreation is disabled for this dataset or whole run, so skipping without error") if ($self->debug); } else { push (@sendFailed, $errmsg); $thisSendFailed = 1; From 1cc6892fcb00b6a3ee05c8ed4342b3f6074de7f2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 12 Mar 2024 10:23:09 +0100 Subject: [PATCH 6/6] lib/ZnapZend/Config.pm: consolidate large comment block --- lib/ZnapZend/Config.pm | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/ZnapZend/Config.pm b/lib/ZnapZend/Config.pm index 8a279c21..b8548342 100644 --- a/lib/ZnapZend/Config.pm +++ b/lib/ZnapZend/Config.pm @@ -91,7 +91,7 @@ my $checkBackupSets = sub { # local "org.znapzend:..." property), or just once for a single # "--runonce=..." backupSet (not recursing into children with # their exceptional settings then, unless also "--recursive"). - + # # In case there is only one property on this dataset, which is the # "enabled" flag and is set to "off"; consider it a normal situation # and do not even notify it. This situation will appear when there @@ -99,11 +99,18 @@ my $checkBackupSets = sub { # Note: backupSets will have at least the key "src". Therefore, we # need to skip the dataset if there are two properties and one of # them is "enabled". - + # + # Similarly for datasets which declare both the "enabled" flag and + # the "recursion" flag (e.g. to prune whole dataset sub-trees from + # backing up with znapzend) by configuring only the root of such + # sub-tree. + # # Likewise, skip checking datasets (enabled or not) that have only # an autoCreation setting for particular destination(s); note that # ZFS property names must be lower-case (so "c" is small here). - # So we prepare a filtered set of configuration keys: + # Hence we prepare a filtered set of configuration keys ("dst" name + # tags are user-provided and not too predictable), so only "src" + # would remain there: my @backupSetKeysFiltered = grep (!/^dst_[^_]+_autocreation$/, keys(%{$backupSet})); my $backupSetKeysFiltered = scalar(@backupSetKeysFiltered); $self->zLog->debug("#checkBackupSets# backupSetKeysFiltered " @@ -119,10 +126,7 @@ my $checkBackupSets = sub { next; } - # Similarly for datasets which declare both the "enabled" flag and - # the "recursion" flag (e.g. to prune whole dataset sub-trees from - # backing up with znapzend) by configuring only the root of such - # sub-tree. + # "src", "enabled" and "recursion" (after disregarding autocreation): if ($backupSetKeysFiltered eq 3 && exists($backupSet->{"enabled"}) && exists($backupSet->{"recursive"})){ next; }