X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=PVE%2FStorage.pm;h=77fdf33e5ac58422e98a59d61ae25aa3d02ae330;hb=7459cb3d912ac172cfcce3bbfcbfc1afba2887ea;hp=47948188a623ac16e753391f7d05922027b8f3d9;hpb=b76774e57fe66a483a7544ec5a05ba2e998eb836;p=pve-storage.git diff --git a/PVE/Storage.pm b/PVE/Storage.pm index 4794818..77fdf33 100755 --- a/PVE/Storage.pm +++ b/PVE/Storage.pm @@ -216,24 +216,6 @@ sub volume_snapshot { } } -sub volume_send { - my ($cfg, $volid, $snap, $ip, $incremental_snap, $verbose, $limit, - $target_path) = @_; - - 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_send($scfg, $storeid, $volname, $ip, $snap, - $incremental_snap, $verbose, $limit, $target_path); - - } elsif ($volid =~ m|^(/.+)$| && -e $volid) { - die "send file/device '$volid' is not possible\n"; - } else { - die "unable to parse volume ID '$volid'\n"; - } -} - sub volume_snapshot_rollback { my ($cfg, $volid, $snap) = @_; @@ -280,6 +262,23 @@ sub volume_has_feature { } } +sub volume_snapshot_list { + my ($cfg, $volid, $prefix) = @_; + + 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); + } 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) = @_; @@ -526,7 +525,7 @@ sub abs_filesystem_path { } sub storage_migrate { - my ($cfg, $volid, $target_host, $target_storeid, $target_volname) = @_; + my ($cfg, $volid, $target_host, $target_storeid, $target_volname, $base_snapshot) = @_; my ($storeid, $volname) = parse_volume_id($volid); $target_volname = $volname if !$target_volname; @@ -547,10 +546,17 @@ sub storage_migrate { local $ENV{RSYNC_RSH} = $ssh; + my $no_incremental = sub { + my ($type) = @_; + die "incremental migration not supported on storage type $type\n" + if defined($base_snapshot); + }; + # only implemented for file system based storage if ($scfg->{path}) { - if ($tcfg->{path}) { + $no_incremental->($scfg->{type}); + if ($tcfg->{path}) { my $src_plugin = PVE::Storage::Plugin->lookup($scfg->{type}); my $dst_plugin = PVE::Storage::Plugin->lookup($tcfg->{type}); my $src = $src_plugin->path($scfg, $volname, $storeid); @@ -617,32 +623,41 @@ sub storage_migrate { if $tcfg->{pool} ne $scfg->{pool}; my (undef, $volname) = parse_volname($cfg, $volid); - my $zfspath = "$scfg->{pool}\/$volname"; - my $snap = ['zfs', 'snapshot', "$zfspath\@__migration__"]; + my @formats = volume_transfer_formats($cfg, $volid, $volid, '__migration__', $base_snapshot, 1); + die "cannot migrate from storage type '$scfg->{type}' to '$tcfg->{type}'\n" if !@formats; + my $format = $formats[0]; - my $send = [['zfs', 'send', '-Rpv', "$zfspath\@__migration__"], ['ssh', "root\@$target_host", - 'zfs', 'recv', $zfspath]]; + my $send = ['pvesm', 'export', $volid, $format, '-', '-snapshot', '__migration__', '-with-snapshots', '1']; + my $recv = ['ssh', "root\@$target_host", '--', 'pvesm', 'import', $volid, $format, '-', '-with-snapshots', '1']; + my $free = ['ssh', "root\@$target_host", '--', 'pvesm', 'free', $volid, '-snapshot', '__migration__']; - my $destroy_target = ['ssh', "root\@$target_host", 'zfs', 'destroy', "$zfspath\@__migration__"]; - run_command($snap); - eval{ - run_command($send); + if (defined($base_snapshot)) { + # Check if the snapshot exists on the remote side: + push @$send, '-base', $base_snapshot; + push @$recv, '-base', $base_snapshot; + } + + volume_snapshot($cfg, $volid, '__migration__'); + eval { + run_command([$send, $recv]); }; my $err = $@; - warn "zfs send/receive failed, cleaning up snapshot(s)..\n" if $err; - eval { run_command(['zfs', 'destroy', "$zfspath\@__migration__"]); }; + warn "send/receive failed, cleaning up snapshot(s)..\n" if $err; + eval { volume_snapshot_delete($cfg, $volid, '__migration__', 0) }; warn "could not remove source snapshot: $@\n" if $@; - eval { run_command($destroy_target); }; - warn "could not remove target snapshot: $@\n" if $@; + if (defined($free)) { + eval { run_command($free) }; + warn "could not remove target snapshot: $@\n" if $@; + } die $err if $err; - } else { die "$errstr - target type $tcfg->{type} is not valid\n"; } } elsif ($scfg->{type} eq 'lvmthin' || $scfg->{type} eq 'lvm') { + $no_incremental->($scfg->{type}); if (($scfg->{type} eq $tcfg->{type}) && ($tcfg->{type} eq 'lvmthin' || $tcfg->{type} eq 'lvm')) { @@ -1454,6 +1469,59 @@ sub extract_vzdump_config { } } +sub volume_export { + my ($cfg, $fh, $volid, $format, $snapshot, $base_snapshot, $with_snapshots) = @_; + + my ($storeid, $volname) = parse_volume_id($volid, 1); + die "cannot export volume '$volid'\n" if !$storeid; + my $scfg = storage_config($cfg, $storeid); + my $plugin = PVE::Storage::Plugin->lookup($scfg->{type}); + return $plugin->volume_export($scfg, $storeid, $fh, $volname, $format, + $snapshot, $base_snapshot, $with_snapshots); +} + +sub volume_import { + my ($cfg, $fh, $volid, $format, $base_snapshot, $with_snapshots) = @_; + + my ($storeid, $volname) = parse_volume_id($volid, 1); + die "cannot import into volume '$volid'\n" if !$storeid; + my $scfg = storage_config($cfg, $storeid); + my $plugin = PVE::Storage::Plugin->lookup($scfg->{type}); + return $plugin->volume_import($scfg, $storeid, $fh, $volname, $format, + $base_snapshot, $with_snapshots); +} + +sub volume_export_formats { + my ($cfg, $volid, $snapshot, $base_snapshot, $with_snapshots) = @_; + + my ($storeid, $volname) = parse_volume_id($volid, 1); + return if !$storeid; + my $scfg = storage_config($cfg, $storeid); + my $plugin = PVE::Storage::Plugin->lookup($scfg->{type}); + return $plugin->volume_export_formats($scfg, $storeid, $volname, + $base_snapshot, $with_snapshots); +} + +sub volume_import_formats { + my ($cfg, $volid, $base_snapshot, $with_snapshots) = @_; + + my ($storeid, $volname) = parse_volume_id($volid, 1); + return if !$storeid; + my $scfg = storage_config($cfg, $storeid); + my $plugin = PVE::Storage::Plugin->lookup($scfg->{type}); + return $plugin->volume_import_formats($scfg, $storeid, $volname, + $base_snapshot, $with_snapshots); +} + +sub volume_transfer_formats { + my ($cfg, $src_volid, $dst_volid, $snapshot, $base_snapshot, $with_snapshots) = @_; + my @export_formats = volume_export_formats($cfg, $src_volid, $snapshot, $base_snapshot, $with_snapshots); + my @import_formats = volume_import_formats($cfg, $dst_volid, $base_snapshot, $with_snapshots); + my %import_hash = map { $_ => 1 } @import_formats; + my @common = grep { $import_hash{$_} } @export_formats; + return @common; +} + # bash completion helper sub complete_storage {