diff --git a/CHANGELIST b/CHANGELIST index d672f28..cc740ba 100644 --- a/CHANGELIST +++ b/CHANGELIST @@ -1,3 +1,9 @@ +1.4.6 added a mollyguard to syncoid to help newbies who try to zfs create a new target dataset + before doing an initial replication, instead of letting the replication itself create + the target. + + added "==0 or die" to all system() calls in syncoid. + 1.4.5 altered shebang to '#!/usr/bin/env perl' for enhanced FreeBSD compatibility 1.4.4 merged pull requests from jjlawren for OmniOS compatibility, added --configdir=/path/to/configs CLI option to sanoid at jjlawrens' request presumably for same @@ -5,16 +11,18 @@ 1.4.3 added SSH persistence to syncoid - using socket speeds up SSH overhead 300%! =) one extra commit to get rid of the "Exit request sent." SSH noise at the end. -1.4.2 removed -r flag for zfs destroy of pruned snapshots in sanoid, which unintentionally caused same-name child snapshots to be deleted - thank you Lenz Weber! +1.4.2 removed -r flag for zfs destroy of pruned snapshots in sanoid, which unintentionally caused same-name + child snapshots to be deleted - thank you Lenz Weber! 1.4.1 updated check_zpool() in sanoid to parse zpool list properly both pre- and post- ZoL v0.6.4 -1.4.0 added findoid tool - find and list all versions of a given file in all available ZFS snapshots. use: findoid /path/to/file +1.4.0 added findoid tool - find and list all versions of a given file in all available ZFS snapshots. + use: findoid /path/to/file 1.3.1 whoops - prevent process_children_only from getting set from blank value in defaults -1.3.0 changed monitor_children_only to process_children_only. which keeps sanoid from messing around with empty parent datasets at all. - also more thoroughly documented features in default config files. +1.3.0 changed monitor_children_only to process_children_only. which keeps sanoid from messing around with + empty parent datasets at all. also more thoroughly documented features in default config files. 1.2.0 added monitor_children_only parameter to sanoid.conf for use with recursive definitions - in cases where container dataset is kept empty diff --git a/VERSION b/VERSION index e516bb9..c514bd8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.5 +1.4.6 diff --git a/findoid b/findoid index e49c887..b19dfba 100755 --- a/findoid +++ b/findoid @@ -11,7 +11,7 @@ use warnings; my $zfs = '/sbin/zfs'; my %args = getargs(@ARGV); -my $progversion = '1.4.5'; +my $progversion = '1.4.6'; if ($args{'version'}) { print "$progversion\n"; exit 0; } diff --git a/sanoid b/sanoid index 8ab0e9e..d44b576 100755 --- a/sanoid +++ b/sanoid @@ -4,7 +4,7 @@ # from http://www.gnu.org/licenses/gpl-3.0.html on 2014-11-17. A copy should also be available in this # project's Git repository at https://github.com/jimsalterjrs/sanoid/blob/master/LICENSE. -my $version = '1.4.5'; +my $version = '1.4.6'; use strict; use Config::IniFiles; # read samba-style conf file @@ -332,7 +332,8 @@ sub take_snapshots { foreach my $snap ( @newsnaps ) { if ($args{'verbose'}) { print "taking snapshot $snap\n"; } if (!$args{'readonly'}) { - system($zfs, "snapshot", "$snap"); + system($zfs, "snapshot", "$snap") == 0 + or die "CRITICAL ERROR: $zfs snapshot $snap failed, $?"; # make sure we don't end up with multiple snapshots with the same ctime sleep 1; } diff --git a/syncoid b/syncoid index 593ab08..a397c0b 100755 --- a/syncoid +++ b/syncoid @@ -4,7 +4,7 @@ # from http://www.gnu.org/licenses/gpl-3.0.html on 2014-11-17. A copy should also be available in this # project's Git repository at https://github.com/jimsalterjrs/sanoid/blob/master/LICENSE. -my $version = '1.4.5'; +my $version = '1.4.6'; use strict; use Data::Dumper; @@ -56,7 +56,9 @@ my %avail = checkcommands(); my %snaps; -## break here to call replication individually so that we can loop across children separately, for recursive replication ## +## break here to call replication individually so that we ## +## can loop across children separately, for recursive ## +## replication ## if (! $args{'recursive'}) { syncdataset($sourcehost, $sourcefs, $targethost, $targetfs); @@ -167,7 +169,8 @@ sub syncdataset { if (iszfsbusy($targethost,$targetfs,$targetisroot)) { die "Cannot sync now: $targetfs is already target of a zfs receive process.\n"; } - system($synccmd); + system($synccmd) == 0 + or die "CRITICAL ERROR: $synccmd failed: $?"; # now do an -I to the new sync snapshot, assuming there were any snapshots # other than the new sync snapshot to begin with, of course @@ -190,7 +193,8 @@ sub syncdataset { print "INFO: Updating new target filesystem with incremental $sourcefs\@$oldestsnap ... $newsyncsnap (~ $disp_pvsize):\n"; if ($debug) { print "DEBUG: $synccmd\n"; } - system($synccmd); + system($synccmd) == 0 + or die "CRITICAL ERROR: $synccmd failed: $?"; # restore original readonly value to target after sync complete setzfsvalue($targethost,$targetfs,$targetisroot,'readonly',$originaltargetreadonly); @@ -202,8 +206,9 @@ sub syncdataset { # get current readonly status of target, then set it to on during sync $originaltargetreadonly = getzfsvalue($targethost,$targetfs,$targetisroot,'readonly'); setzfsvalue($targethost,$targetfs,$targetisroot,'readonly','on'); + my $targetsize = getzfsvalue($targethost,$targetfs,$targetisroot,'-p used'); - my $matchingsnap = getmatchingsnapshot(\%snaps); + my $matchingsnap = getmatchingsnapshot($targetsize, \%snaps); # make sure target is (still) not currently in receive. if (iszfsbusy($targethost,$targetfs,$targetisroot)) { @@ -229,7 +234,8 @@ sub syncdataset { print "Sending incremental $sourcefs\@$matchingsnap ... $newsyncsnap (~ $disp_pvsize):\n"; if ($debug) { print "DEBUG: $synccmd\n"; } - system("$synccmd"); + system("$synccmd") == 0 + or die "CRITICAL ERROR: $synccmd failed: $?"; # restore original readonly value to target after sync complete setzfsvalue($targethost,$targetfs,$targetisroot,'readonly',$originaltargetreadonly); @@ -489,7 +495,8 @@ sub setzfsvalue { my $mysudocmd; if ($isroot) { $mysudocmd = ''; } else { $mysudocmd = $sudocmd; } if ($debug) { print "$rhost $mysudocmd $zfscmd set $property=$value $fs\n"; } - system("$rhost $mysudocmd $zfscmd set $property=$value $fs"); + system("$rhost $mysudocmd $zfscmd set $property=$value $fs") == 0 + or die "CRITICAL ERROR: $rhost $mysudocmd $zfscmd set $property=$value $fs died: $?"; return; } @@ -628,7 +635,8 @@ sub pruneoldsyncsnaps { if ($rhost ne '') { $prunecmd = '"' . $prunecmd . '"'; } if ($debug) { print "DEBUG: pruning up to $maxsnapspercmd obsolete sync snapshots...\n"; } if ($debug) { print "DEBUG: $rhost $prunecmd\n"; } - system("$rhost $prunecmd"); + system("$rhost $prunecmd") == 0 + or die "CRITICAL ERROR: $rhost $prunecmd failed: $?"; $prunecmd = ''; $counter = 0; } @@ -640,19 +648,36 @@ sub pruneoldsyncsnaps { if ($rhost ne '') { $prunecmd = '"' . $prunecmd . '"'; } if ($debug) { print "DEBUG: pruning up to $maxsnapspercmd obsolete sync snapshots...\n"; } if ($debug) { print "DEBUG: $rhost $prunecmd\n"; } - system("$rhost $prunecmd"); + system("$rhost $prunecmd") == 0 + or die "CRITICAL ERROR: $rhost $prunecmd failed: $?"; } return; } sub getmatchingsnapshot { - my $snaps = shift; + my ($targetsize, $snaps) = shift; foreach my $snap ( sort { $snaps{'source'}{$b}{'ctime'}<=>$snaps{'source'}{$a}{'ctime'} } keys %{ $snaps{'source'} }) { if ($snaps{'source'}{$snap}{'ctime'} == $snaps{'target'}{$snap}{'ctime'}) { return $snap; } } - print "UNEXPECTED ERROR: target exists but has no matching snapshots!\n"; + + # if we got this far, we failed to find a matching snapshot. + + print "\n"; + print "CRITICAL ERROR: Target exists but has no matching snapshots!\n"; + print " Replication to target would require destroying existing\n"; + print " target. Cowardly refusing to destroy your existing target.\n\n"; + + # experience tells me we need a mollyguard for people who try to + # zfs create targetpool/targetsnap ; syncoid sourcepool/sourcesnap targetpool/targetsnap ... + + if ( $targetsize < (64*1024*1024) ) { + print " NOTE: Target dataset is < 64MB used - did you mistakenly run\n"; + print " \`zfs create $args{'target'}\` on the target? ZFS initial\n"; + print " replication must be to a NON EXISTENT DATASET, which will\n"; + print " then be CREATED BY the initial replication process.\n\n"; + } exit 256; } @@ -665,7 +690,8 @@ sub newsyncsnap { my %date = getdate(); my $snapname = "syncoid\_$hostid\_$date{'stamp'}"; my $snapcmd = "$rhost $mysudocmd $zfscmd snapshot $fs\@$snapname\n"; - system($snapcmd); + system($snapcmd) == 0 + or die "CRITICAL ERROR: $snapcmd failed: $?"; return $snapname; }