diff --git a/ApiChangeLog b/ApiChangeLog new file mode 100644 index 0000000..8c119c5 --- /dev/null +++ b/ApiChangeLog @@ -0,0 +1,25 @@ +# API Versioning ChangeLog + +Our API versioning contains an `APIVER` and an `APIAGE`. +The `APIAGE` is the number of versions we're backward compatible with. (iow. things got added +without breaking anything unaware of it.) + +Future changes should be documented in here. + +## Version 9: (AGE resets to 0): + +* volume_import_formats gets a new parameter *inserted*: + + Old signature: + sub($plugin, $scfg, $storeid, $volname, $base_snapshot, $with_snapshots) + New signature: + sub($plugin, $scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots) + + This is now the same as `volume_export_formats`. + + The same goes for calls to `PVE::Storage::volume_import_formats`, which now + takes a `$snapshot` parameter in the same place. + +* $with_snapshots *may* now be an array reference containing an ordered list of + snapshots, but *may* also just be a boolean, and the contained list *may* be + ignored, so it can still be treated as a boolean. diff --git a/PVE/CLI/pvesm.pm b/PVE/CLI/pvesm.pm index d28f1ba..4491107 100755 --- a/PVE/CLI/pvesm.pm +++ b/PVE/CLI/pvesm.pm @@ -276,12 +276,23 @@ __PACKAGE__->register_method ({ optional => 1, default => 0, }, + 'snapshot-list' => { + description => "Ordered list of snapshots to transfer", + type => 'string', + format => 'string-list', + optional => 1, + }, }, }, returns => { type => 'null' }, code => sub { my ($param) = @_; + my $with_snapshots = $param->{'with-snapshots'}; + if (defined(my $list = $param->{'snapshot-list'})) { + $with_snapshots = PVE::Tools::split_list($list); + } + my $filename = $param->{filename}; my $outfh; @@ -295,7 +306,7 @@ __PACKAGE__->register_method ({ eval { my $cfg = PVE::Storage::config(); PVE::Storage::volume_export($cfg, $outfh, $param->{volume}, $param->{format}, - $param->{snapshot}, $param->{base}, $param->{'with-snapshots'}); + $param->{snapshot}, $param->{base}, $with_snapshots); }; my $err = $@; if ($filename ne '-') { @@ -361,6 +372,13 @@ __PACKAGE__->register_method ({ optional => 1, default => 0, }, + snapshot => { + description => "The current-state snapshot if the stream contains snapshots", + type => 'string', + pattern => qr/[a-z0-9_\-]{1,40}/i, + maxLength => 40, + optional => 1, + }, }, }, returns => { type => 'string' }, @@ -436,7 +454,8 @@ __PACKAGE__->register_method ({ my $volume = $param->{volume}; my $delete = $param->{'delete-snapshot'}; my $imported_volid = PVE::Storage::volume_import($cfg, $infh, $volume, $param->{format}, - $param->{base}, $param->{'with-snapshots'}, $param->{'allow-rename'}); + $param->{snapshot}, $param->{base}, $param->{'with-snapshots'}, + $param->{'allow-rename'}); PVE::Storage::volume_snapshot_delete($cfg, $imported_volid, $delete) if defined($delete); return $imported_volid; diff --git a/PVE/Storage.pm b/PVE/Storage.pm index a36842b..a024953 100755 --- a/PVE/Storage.pm +++ b/PVE/Storage.pm @@ -41,11 +41,11 @@ use PVE::Storage::PBSPlugin; use PVE::Storage::BTRFSPlugin; # Storage API version. Increment it on changes in storage API interface. -use constant APIVER => 8; +use constant APIVER => 9; # Age is the number of versions we're backward compatible with. # This is like having 'current=APIVER' and age='APIAGE' in libtool, # see https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html -use constant APIAGE => 7; +use constant APIAGE => 0; # load standard plugins PVE::Storage::DirPlugin->register(); @@ -716,7 +716,8 @@ sub storage_migrate { my $send = ['pvesm', 'export', $volid, $format, '-', '-with-snapshots', $with_snapshots]; my $recv = [@$ssh, '--', 'pvesm', 'import', $target_volid, $format, $import_fn, '-with-snapshots', $with_snapshots]; if (defined($snapshot)) { - push @$send, '-snapshot', $snapshot + push @$send, '-snapshot', $snapshot; + push @$recv, '-snapshot', $snapshot; } if ($migration_snapshot) { push @$recv, '-delete-snapshot', $snapshot; @@ -726,7 +727,7 @@ sub storage_migrate { if (defined($base_snapshot)) { # Check if the snapshot exists on the remote side: push @$send, '-base', $base_snapshot; - push @$recv, '-base', $base_snapshot; + push @$recv, '-base', $base_snapshot if $target_apiver >= 9; } my $new_volid; @@ -1714,7 +1715,7 @@ sub prune_mark_backup_group { } } -sub volume_export { +sub volume_export : prototype($$$$$$$) { my ($cfg, $fh, $volid, $format, $snapshot, $base_snapshot, $with_snapshots) = @_; my ($storeid, $volname) = parse_volume_id($volid, 1); @@ -1725,18 +1726,27 @@ sub volume_export { $snapshot, $base_snapshot, $with_snapshots); } -sub volume_import { - my ($cfg, $fh, $volid, $format, $base_snapshot, $with_snapshots, $allow_rename) = @_; +sub volume_import : prototype($$$$$$$$) { + my ($cfg, $fh, $volid, $format, $snapshot, $base_snapshot, $with_snapshots, $allow_rename) = @_; 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, $allow_rename) // $volid; + return $plugin->volume_import( + $scfg, + $storeid, + $fh, + $volname, + $format, + $snapshot, + $base_snapshot, + $with_snapshots, + $allow_rename, + ) // $volid; } -sub volume_export_formats { +sub volume_export_formats : prototype($$$$$) { my ($cfg, $volid, $snapshot, $base_snapshot, $with_snapshots) = @_; my ($storeid, $volname) = parse_volume_id($volid, 1); @@ -1748,21 +1758,27 @@ sub volume_export_formats { $with_snapshots); } -sub volume_import_formats { - my ($cfg, $volid, $base_snapshot, $with_snapshots) = @_; +sub volume_import_formats : prototype($$$$$) { + 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_import_formats($scfg, $storeid, $volname, - $base_snapshot, $with_snapshots); + return $plugin->volume_import_formats( + $scfg, + $storeid, + $volname, + $snapshot, + $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_formats = volume_import_formats($cfg, $dst_volid, $snapshot, $base_snapshot, $with_snapshots); my %import_hash = map { $_ => 1 } @import_formats; my @common = grep { $import_hash{$_} } @export_formats; return @common; diff --git a/PVE/Storage/LVMPlugin.pm b/PVE/Storage/LVMPlugin.pm index fb4acdb..039bfc1 100644 --- a/PVE/Storage/LVMPlugin.pm +++ b/PVE/Storage/LVMPlugin.pm @@ -603,7 +603,7 @@ sub volume_has_feature { sub volume_export_formats { my ($class, $scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots) = @_; return () if defined($snapshot); # lvm-thin only - return volume_import_formats($class, $scfg, $storeid, $volname, $base_snapshot, $with_snapshots); + return volume_import_formats($class, $scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots); } sub volume_export { @@ -627,14 +627,14 @@ sub volume_export { } sub volume_import_formats { - my ($class, $scfg, $storeid, $volname, $base_snapshot, $with_snapshots) = @_; + my ($class, $scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots) = @_; return () if $with_snapshots; # not supported return () if defined($base_snapshot); # not supported return ('raw+size'); } sub volume_import { - my ($class, $scfg, $storeid, $fh, $volname, $format, $base_snapshot, $with_snapshots, $allow_rename) = @_; + my ($class, $scfg, $storeid, $fh, $volname, $format, $snapshot, $base_snapshot, $with_snapshots, $allow_rename) = @_; die "volume import format $format not available for $class\n" if $format ne 'raw+size'; die "cannot import volumes together with their snapshots in $class\n" diff --git a/PVE/Storage/Plugin.pm b/PVE/Storage/Plugin.pm index 080835f..b1865cb 100644 --- a/PVE/Storage/Plugin.pm +++ b/PVE/Storage/Plugin.pm @@ -1411,7 +1411,7 @@ sub volume_export_formats { # Import data from a stream, creating a new or replacing or adding to an existing volume. sub volume_import { - my ($class, $scfg, $storeid, $fh, $volname, $format, $base_snapshot, $with_snapshots, $allow_rename) = @_; + my ($class, $scfg, $storeid, $fh, $volname, $format, $snapshot, $base_snapshot, $with_snapshots, $allow_rename) = @_; die "volume import format '$format' not available for $class\n" if $format !~ /^(raw|tar|qcow2|vmdk)\+size$/; @@ -1471,7 +1471,7 @@ sub volume_import { } sub volume_import_formats { - my ($class, $scfg, $storeid, $volname, $base_snapshot, $with_snapshots) = @_; + my ($class, $scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots) = @_; if ($scfg->{path} && !defined($base_snapshot)) { my $format = ($class->parse_volname($volname))[6]; if ($with_snapshots) { diff --git a/PVE/Storage/ZFSPoolPlugin.pm b/PVE/Storage/ZFSPoolPlugin.pm index 2e2abe3..c4be70f 100644 --- a/PVE/Storage/ZFSPoolPlugin.pm +++ b/PVE/Storage/ZFSPoolPlugin.pm @@ -747,7 +747,7 @@ sub volume_export_formats { } sub volume_import { - my ($class, $scfg, $storeid, $fh, $volname, $format, $base_snapshot, $with_snapshots, $allow_rename) = @_; + my ($class, $scfg, $storeid, $fh, $volname, $format, $snapshot, $base_snapshot, $with_snapshots, $allow_rename) = @_; die "unsupported import stream format for $class: $format\n" if $format ne 'zfs'; @@ -784,9 +784,9 @@ sub volume_import { } sub volume_import_formats { - my ($class, $scfg, $storeid, $volname, $base_snapshot, $with_snapshots) = @_; + my ($class, $scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots) = @_; - return $class->volume_export_formats($scfg, $storeid, $volname, undef, $base_snapshot, $with_snapshots); + return $class->volume_export_formats($scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots); } 1;