From aefe82ea034b3d796c59034867fe17892ba18080 Mon Sep 17 00:00:00 2001 From: Wolfgang Link Date: Mon, 24 Apr 2017 17:15:27 +0200 Subject: [PATCH] Include new storage function volume_snapshot_list. Returns a list of snapshots (youngest snap first) form a given volid. It is possible to use a prefix to filter the list. --- PVE/Storage.pm | 17 ++++++++++++++++ PVE/Storage/Plugin.pm | 9 +++++++++ PVE/Storage/ZFSPlugin.pm | 6 ++++++ PVE/Storage/ZFSPoolPlugin.pm | 39 +++++++++++++++++++++++++++++++++++- 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/PVE/Storage.pm b/PVE/Storage.pm index 4794818..8fe9f4b 100755 --- a/PVE/Storage.pm +++ b/PVE/Storage.pm @@ -280,6 +280,23 @@ sub volume_has_feature { } } +sub volume_snapshot_list { + my ($cfg, $volid, $prefix, $ip) = @_; + + my ($storeid, $volname) = parse_volume_id($volid, 1); + if ($storeid) { + my $scfg = storage_config($cfg, $storeid); + my $plugin = PVE::Storage::Plugin->lookup($scfg->{type}); + return $plugin->volume_snapshot_list($scfg, $storeid, $volname, $prefix, $ip); + } elsif ($volid =~ m|^(/.+)$| && -e $volid) { + die "send file/device '$volid' is not possible\n"; + } else { + die "unable to parse volume ID '$volid'\n"; + } + # return an empty array if dataset does not exist. + # youngest snap first +} + sub get_image_dir { my ($cfg, $storeid, $vmid) = @_; diff --git a/PVE/Storage/Plugin.pm b/PVE/Storage/Plugin.pm index d0df1f9..641ab04 100644 --- a/PVE/Storage/Plugin.pm +++ b/PVE/Storage/Plugin.pm @@ -832,6 +832,15 @@ sub status { return ($res->{total}, $res->{avail}, $res->{used}, 1); } +sub volume_snapshot_list { + my ($class, $scfg, $storeid, $volname, $prefix, $ip) = @_; + + # implement in subclass + die "Volume_snapshot_list is not implemented for $class"; + + # retrun an empty array if dataset does not exist. +} + sub activate_storage { my ($class, $storeid, $scfg, $cache) = @_; diff --git a/PVE/Storage/ZFSPlugin.pm b/PVE/Storage/ZFSPlugin.pm index 9007193..c7c7ba3 100644 --- a/PVE/Storage/ZFSPlugin.pm +++ b/PVE/Storage/ZFSPlugin.pm @@ -369,6 +369,12 @@ sub volume_has_feature { return undef; } +sub volume_snapshot_list { + my ($class, $scfg, $storeid, $volname, $prefix, $ip) = @_; + # return an empty array if dataset does not exist. + die "Volume_snapshot_list is not implemented for ZFS over iSCSI.\n"; +} + sub activate_storage { my ($class, $storeid, $scfg, $cache) = @_; diff --git a/PVE/Storage/ZFSPoolPlugin.pm b/PVE/Storage/ZFSPoolPlugin.pm index 5b98378..a212191 100644 --- a/PVE/Storage/ZFSPoolPlugin.pm +++ b/PVE/Storage/ZFSPoolPlugin.pm @@ -7,6 +7,7 @@ use POSIX; use PVE::Tools qw(run_command); use PVE::Storage::Plugin; use PVE::RPCEnvironment; +use Net::IP; use base qw(PVE::Storage::Plugin); @@ -495,7 +496,11 @@ sub volume_send { my $cmdrecv = []; - push @$cmdrecv, 'ssh', '-o', 'BatchMode=yes', "root\@${ip}", '--' if $ip; + if ($ip) { + $ip = "[$ip]" if Net::IP::ip_is_ipv6($ip); + push @$cmdrecv, 'ssh', '-o', 'BatchMode=yes', "root\@${ip}", '--'; + } + push @$cmdrecv, 'zfs', 'recv', '-F', '--'; $zpath = $target_path if defined($target_path); @@ -541,6 +546,38 @@ sub volume_rollback_is_possible { return 1; } +sub volume_snapshot_list { + my ($class, $scfg, $storeid, $volname, $prefix, $ip) = @_; + + my ($vtype, $name, $vmid) = $class->parse_volname($volname); + + my $zpath = "$scfg->{pool}/$name"; + + $prefix = '' if !defined($prefix); + my $snaps = []; + + my $cmd = ['zfs', 'list', '-r', '-H', '-S', 'name', '-t', 'snap', '-o', + 'name', $zpath]; + + if ($ip) { + $ip = "[$ip]" if Net::IP::ip_is_ipv6($ip); + unshift @$cmd, 'ssh', '-o', ' BatchMode=yes', "root\@${ip}", '--'; + } + + my $outfunc = sub { + my $line = shift; + + if ($line =~ m/^\Q$zpath\E@(\Q$prefix\E.*)$/) { + push @$snaps, $1; + } + }; + + eval { run_command( [$cmd], outfunc => $outfunc , errfunc => sub{}); }; + + # return an empty array if dataset does not exist. + return $snaps; +} + sub activate_storage { my ($class, $storeid, $scfg, $cache) = @_; -- 2.39.2