1 |
dpavlin |
267 |
#!/usr/bin/perl |
2 |
|
|
use warnings; |
3 |
|
|
use strict; |
4 |
|
|
|
5 |
|
|
use Net::OpenSSH; |
6 |
|
|
use Data::Dump qw(dump); |
7 |
|
|
use List::Util qw(first); |
8 |
dpavlin |
268 |
use Time::Hires; |
9 |
dpavlin |
267 |
|
10 |
|
|
my $arh = Net::OpenSSH->new('root@10.60.0.204'); |
11 |
|
|
my $dev = Net::OpenSSH->new('root@10.60.0.202'); |
12 |
|
|
|
13 |
|
|
sub on { |
14 |
|
|
my ($ssh,$command) = @_; |
15 |
|
|
warn "## ", $ssh->get_host, "> $command\n"; |
16 |
|
|
if ( $command =~ m/zfs list/ ) { |
17 |
|
|
map { |
18 |
|
|
chomp; $_; |
19 |
|
|
} $ssh->capture($command); |
20 |
|
|
} else { |
21 |
|
|
$ssh->capture($command); |
22 |
|
|
} |
23 |
|
|
} |
24 |
|
|
|
25 |
|
|
print on $arh => 'zpool status'; |
26 |
|
|
print on $dev => 'zpool status'; |
27 |
|
|
|
28 |
|
|
my @arh = on $arh => 'zfs list -H -o name'; |
29 |
|
|
my @dev = on $dev => 'zfs list -H -o name'; |
30 |
|
|
|
31 |
|
|
warn "# ",dump( \@arh, \@dev ); |
32 |
|
|
|
33 |
|
|
my $from_pool = $arh[0]; |
34 |
|
|
my $to_pool = $dev[0]; |
35 |
|
|
|
36 |
|
|
sub snapshots_from { |
37 |
|
|
my ($ssh) = @_; |
38 |
|
|
my $host = $ssh->get_host; |
39 |
|
|
|
40 |
|
|
my $snapshot; |
41 |
|
|
|
42 |
|
|
my @snapshots = on $ssh => 'zfs list -H -t snapshot -o name'; |
43 |
|
|
die $ssh->error if $ssh->error; |
44 |
|
|
foreach my $s (@snapshots) { |
45 |
|
|
my ($fs,$name) = split(/\@/,$s); |
46 |
|
|
push @{ $snapshot->{$fs} }, $name; |
47 |
|
|
} |
48 |
|
|
|
49 |
dpavlin |
268 |
# warn "snapshots_from $host ",dump($snapshot),$/; |
50 |
dpavlin |
267 |
|
51 |
|
|
return $snapshot; |
52 |
|
|
} |
53 |
|
|
|
54 |
|
|
foreach my $fs ( @arh ) { |
55 |
|
|
|
56 |
|
|
my $name = $fs; |
57 |
|
|
$name =~ s{^$from_pool/}{} || next; # FIXME skip top-level fs |
58 |
|
|
warn "? $name"; |
59 |
|
|
|
60 |
|
|
my $arh_snapshot = snapshots_from $arh; |
61 |
|
|
if ( ! exists( $arh_snapshot->{$fs} ) ) { |
62 |
|
|
|
63 |
|
|
my $snapshot = $fs . '@send'; |
64 |
|
|
print on $arh => "zfs snapshot $snapshot"; |
65 |
|
|
die $arh->error if $arh->error; |
66 |
|
|
$arh_snapshot = snapshots_from $arh; |
67 |
|
|
} |
68 |
|
|
|
69 |
|
|
my $max_snapshot = $#{ $arh_snapshot->{$fs} }; |
70 |
|
|
warn "$max_snapshot snapshots of $fs on arh\n"; |
71 |
|
|
|
72 |
|
|
my $to_dev = "$to_pool/$name"; |
73 |
|
|
|
74 |
|
|
foreach my $i ( 0 .. $max_snapshot ) { |
75 |
|
|
my $snap = $arh_snapshot->{$fs}->[$i] || die "no snap"; |
76 |
|
|
|
77 |
|
|
my $dev_snapshot = snapshots_from $dev; |
78 |
|
|
if ( exists $dev_snapshot->{$to_dev} ) { |
79 |
|
|
if ( first { /^\Q$snap\E$/ } @{ $dev_snapshot->{$to_dev} } ) { |
80 |
|
|
warn "+ $name exists\n"; |
81 |
|
|
next; |
82 |
|
|
} else { |
83 |
|
|
warn "- $name missing\n"; |
84 |
|
|
} |
85 |
|
|
} else { |
86 |
|
|
warn "$name not found on target yet"; |
87 |
|
|
} |
88 |
|
|
|
89 |
|
|
my $snapshot; |
90 |
|
|
if ( $i == 0 ) { |
91 |
|
|
$snapshot = "$from_pool/$name\@$snap"; |
92 |
|
|
} else { |
93 |
|
|
my $prev = $arh_snapshot->{$fs}->[$i-1] || die "no prev"; |
94 |
|
|
$snapshot = "-i $from_pool/$name\@$prev $from_pool/$name\@$snap"; |
95 |
|
|
} |
96 |
|
|
|
97 |
|
|
warn "zfs transfer $snapshot -> $to_dev"; |
98 |
|
|
|
99 |
|
|
my $t = time(); |
100 |
|
|
|
101 |
|
|
my $recv = "nc -w 5 -l -p 8888 | zfs receive $to_dev"; |
102 |
|
|
warn ">> $recv\n"; |
103 |
|
|
my ($rin1,$pid1) = $dev->pipe_in($recv); |
104 |
|
|
warn ">> pid: $pid1"; |
105 |
|
|
|
106 |
dpavlin |
268 |
sleep 0.1; # FIXME wait for netcat to start |
107 |
|
|
|
108 |
dpavlin |
267 |
my $send = "zfs send $snapshot | nc -q 0 -w 5 10.60.0.202 8888"; |
109 |
|
|
warn "<< $send\n"; |
110 |
|
|
$arh->system($send); |
111 |
|
|
|
112 |
|
|
$t = time() - $t; |
113 |
|
|
warn "took $t seconds to complete\n"; |
114 |
|
|
|
115 |
|
|
$dev->system("zfs set readonly=on $to_pool/$name") if $i == 0; |
116 |
|
|
die $dev->error if $dev->error; |
117 |
|
|
|
118 |
dpavlin |
268 |
$dev_snapshot = snapshots_from $dev; |
119 |
|
|
die "can't find new snapshot $snap" unless $dev_snapshot->{$to_dev}; |
120 |
|
|
|
121 |
dpavlin |
267 |
} |
122 |
|
|
|
123 |
|
|
} |