implemented parsing of provided zfs send/recv options and whitelisting for each use case as needed
This commit is contained in:
parent
9ec0c0bfb1
commit
c5eebbe81d
89
syncoid
89
syncoid
|
@ -27,14 +27,14 @@ GetOptions(\%args, "no-command-checks", "monitor-version", "compress=s", "dumpsn
|
||||||
|
|
||||||
my %compressargs = %{compressargset($args{'compress'} || 'default')}; # Can't be done with GetOptions arg, as default still needs to be set
|
my %compressargs = %{compressargset($args{'compress'} || 'default')}; # Can't be done with GetOptions arg, as default still needs to be set
|
||||||
|
|
||||||
my $sendoptions = '';
|
my @sendoptions = ();
|
||||||
if (length $args{'sendoptions'}) {
|
if (length $args{'sendoptions'}) {
|
||||||
$sendoptions = $args{'sendoptions'}
|
@sendoptions = parsespecialoptions($args{'sendoptions'});
|
||||||
}
|
}
|
||||||
|
|
||||||
my $recvoptions = '';
|
my @recvoptions = ();
|
||||||
if (length $args{'recvoptions'}) {
|
if (length $args{'recvoptions'}) {
|
||||||
$recvoptions = $args{'recvoptions'}
|
@recvoptions = parsespecialoptions($args{'recvoptions'});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -352,6 +352,9 @@ sub syncdataset {
|
||||||
# with ZFS on Linux (possibly OpenZFS in general) when setting/unsetting readonly.
|
# with ZFS on Linux (possibly OpenZFS in general) when setting/unsetting readonly.
|
||||||
#my $originaltargetreadonly;
|
#my $originaltargetreadonly;
|
||||||
|
|
||||||
|
my $sendoptions = getoptionsline(\@sendoptions, ('D','L','P','R','c','e','p','v','w'));
|
||||||
|
my $recvoptions = getoptionsline(\@recvoptions, ('o','x','u','v'));
|
||||||
|
|
||||||
# sync 'em up.
|
# sync 'em up.
|
||||||
if (! $targetexists) {
|
if (! $targetexists) {
|
||||||
# do an initial sync from the oldest source snapshot
|
# do an initial sync from the oldest source snapshot
|
||||||
|
@ -470,6 +473,7 @@ sub syncdataset {
|
||||||
# and because this will ony resume the receive to the next
|
# and because this will ony resume the receive to the next
|
||||||
# snapshot, do a normal sync after that
|
# snapshot, do a normal sync after that
|
||||||
if (defined($receivetoken)) {
|
if (defined($receivetoken)) {
|
||||||
|
$sendoptions = getoptionsline(\@sendoptions, ('P','e','v','w'));
|
||||||
my $sendcmd = "$sourcesudocmd $zfscmd send $sendoptions -t $receivetoken";
|
my $sendcmd = "$sourcesudocmd $zfscmd send $sendoptions -t $receivetoken";
|
||||||
my $recvcmd = "$targetsudocmd $zfscmd receive $recvoptions $receiveextraargs $forcedrecv $targetfsescaped";
|
my $recvcmd = "$targetsudocmd $zfscmd receive $recvoptions $receiveextraargs $forcedrecv $targetfsescaped";
|
||||||
my $pvsize = getsendsize($sourcehost,"","",$sourceisroot,$receivetoken);
|
my $pvsize = getsendsize($sourcehost,"","",$sourceisroot,$receivetoken);
|
||||||
|
@ -619,9 +623,9 @@ sub syncdataset {
|
||||||
my $pvsize = 0;
|
my $pvsize = 0;
|
||||||
my $disp_pvsize = "UNKNOWN";
|
my $disp_pvsize = "UNKNOWN";
|
||||||
|
|
||||||
|
$sendoptions = getoptionsline(\@sendoptions, ('L','c','e','w'));
|
||||||
if ($nextsnapshot) {
|
if ($nextsnapshot) {
|
||||||
my $nextsnapshotescaped = escapeshellparam($nextsnapshot);
|
my $nextsnapshotescaped = escapeshellparam($nextsnapshot);
|
||||||
|
|
||||||
my $sendcmd = "$sourcesudocmd $zfscmd send $sendoptions -i $sourcefsescaped#$bookmarkescaped $sourcefsescaped\@$nextsnapshotescaped";
|
my $sendcmd = "$sourcesudocmd $zfscmd send $sendoptions -i $sourcefsescaped#$bookmarkescaped $sourcefsescaped\@$nextsnapshotescaped";
|
||||||
my $recvcmd = "$targetsudocmd $zfscmd receive $recvoptions $receiveextraargs $forcedrecv $targetfsescaped";
|
my $recvcmd = "$targetsudocmd $zfscmd receive $recvoptions $receiveextraargs $forcedrecv $targetfsescaped";
|
||||||
my $synccmd = buildsynccmd($sendcmd,$recvcmd,$pvsize,$sourceisroot,$targetisroot);
|
my $synccmd = buildsynccmd($sendcmd,$recvcmd,$pvsize,$sourceisroot,$targetisroot);
|
||||||
|
@ -654,6 +658,7 @@ sub syncdataset {
|
||||||
# do a normal replication if bookmarks aren't used or if previous
|
# do a normal replication if bookmarks aren't used or if previous
|
||||||
# bookmark replication was only done to the next oldest snapshot
|
# bookmark replication was only done to the next oldest snapshot
|
||||||
if (!$bookmark || $nextsnapshot) {
|
if (!$bookmark || $nextsnapshot) {
|
||||||
|
$sendoptions = getoptionsline(\@sendoptions, ('D','L','P','R','c','e','p','v','w'));
|
||||||
my $sendcmd = "$sourcesudocmd $zfscmd send $sendoptions $args{'streamarg'} $sourcefsescaped\@$matchingsnapescaped $sourcefsescaped\@$newsyncsnapescaped";
|
my $sendcmd = "$sourcesudocmd $zfscmd send $sendoptions $args{'streamarg'} $sourcefsescaped\@$matchingsnapescaped $sourcefsescaped\@$newsyncsnapescaped";
|
||||||
my $recvcmd = "$targetsudocmd $zfscmd receive $recvoptions $receiveextraargs $forcedrecv $targetfsescaped";
|
my $recvcmd = "$targetsudocmd $zfscmd receive $recvoptions $receiveextraargs $forcedrecv $targetfsescaped";
|
||||||
my $pvsize = getsendsize($sourcehost,"$sourcefs\@$matchingsnap","$sourcefs\@$newsyncsnap",$sourceisroot);
|
my $pvsize = getsendsize($sourcehost,"$sourcefs\@$matchingsnap","$sourcefs\@$newsyncsnap",$sourceisroot);
|
||||||
|
@ -1398,6 +1403,12 @@ sub getsendsize {
|
||||||
$snaps = "-t $receivetoken";
|
$snaps = "-t $receivetoken";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $sendoptions;
|
||||||
|
if (defined($receivetoken)) {
|
||||||
|
$sendoptions = getoptionsline(\@sendoptions, ('e', 'w'));
|
||||||
|
} else {
|
||||||
|
$sendoptions = getoptionsline(\@sendoptions, ('D','L','R','c','e','p','v','w'));
|
||||||
|
}
|
||||||
my $getsendsizecmd = "$sourcessh $mysudocmd $zfscmd send $sendoptions -nP $snaps";
|
my $getsendsizecmd = "$sourcessh $mysudocmd $zfscmd send $sendoptions -nP $snaps";
|
||||||
if ($debug) { print "DEBUG: getting estimated transfer size from source $sourcehost using \"$getsendsizecmd 2>&1 |\"...\n"; }
|
if ($debug) { print "DEBUG: getting estimated transfer size from source $sourcehost using \"$getsendsizecmd 2>&1 |\"...\n"; }
|
||||||
|
|
||||||
|
@ -1479,6 +1490,70 @@ sub getreceivetoken() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub parsespecialoptions {
|
||||||
|
my ($line) = @_;
|
||||||
|
|
||||||
|
print("$line\n");
|
||||||
|
|
||||||
|
my @options = ();
|
||||||
|
|
||||||
|
my @values = split(/ /, $line);
|
||||||
|
|
||||||
|
my $optionValue = 0;
|
||||||
|
my $lastOption;
|
||||||
|
|
||||||
|
foreach my $value (@values) {
|
||||||
|
if ($optionValue ne 0) {
|
||||||
|
my %item = (
|
||||||
|
"option" => $lastOption,
|
||||||
|
"line" => "-$lastOption $value",
|
||||||
|
);
|
||||||
|
|
||||||
|
push @options, \%item;
|
||||||
|
$optionValue = 0;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $char (split //, $value) {
|
||||||
|
if ($optionValue ne 0) {
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($char eq 'o' || $char eq 'x') {
|
||||||
|
$lastOption = $char;
|
||||||
|
$optionValue = 1;
|
||||||
|
} else {
|
||||||
|
my %item = (
|
||||||
|
"option" => $char,
|
||||||
|
"line" => "-$char",
|
||||||
|
);
|
||||||
|
|
||||||
|
push @options, \%item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return @options;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getoptionsline {
|
||||||
|
my ($options_ref, @allowed) = @_;
|
||||||
|
|
||||||
|
my $line = '';
|
||||||
|
|
||||||
|
foreach my $value (@{ $options_ref }) {
|
||||||
|
if (@allowed) {
|
||||||
|
if (!grep( /^$$value{'option'}$/, @allowed) ) {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$line = "$line$$value{'line'} ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
@ -1509,8 +1584,8 @@ Options:
|
||||||
--no-clone-rollback Does not rollback clones on target
|
--no-clone-rollback Does not rollback clones on target
|
||||||
--no-rollback Does not rollback clones or snapshots on target (it probably requires a readonly target)
|
--no-rollback Does not rollback clones or snapshots on target (it probably requires a readonly target)
|
||||||
--exclude=REGEX Exclude specific datasets which match the given regular expression. Can be specified multiple times
|
--exclude=REGEX Exclude specific datasets which match the given regular expression. Can be specified multiple times
|
||||||
--sendoptions=OPTIONS DANGER: Inject OPTIONS into zfs send, e.g. syncoid --sendoptions="-Lce" sets zfs send -Lce ...
|
--sendoptions=OPTIONS Use advanced options for zfs send (the arguments are filterd as needed), e.g. syncoid --sendoptions="Lc e" sets zfs send -L -c -e ...
|
||||||
--recvoptions=OPTIONS DANGER: Inject OPTIONS into zfs received, e.g. syncoid --recvoptions="-x property" sets zfs receive -x property ...
|
--recvoptions=OPTIONS Use advanced options for zfs receive (the arguments are filterd as needed), e.g. syncoid --recvoptions="ux recordsize o compression=lz4" sets zfs receive -u -x recordsize -o compression=lz4 ...
|
||||||
--sshkey=FILE Specifies a ssh public key to use to connect
|
--sshkey=FILE Specifies a ssh public key to use to connect
|
||||||
--sshport=PORT Connects to remote on a particular port
|
--sshport=PORT Connects to remote on a particular port
|
||||||
--sshcipher|c=CIPHER Passes CIPHER to ssh to use a particular cipher set
|
--sshcipher|c=CIPHER Passes CIPHER to ssh to use a particular cipher set
|
||||||
|
|
Loading…
Reference in New Issue