when 'import-from' contains a disk image that needs extraction (currently only from an 'ova' archive), do that in 'create_disks' and overwrite the '$source' volid.
Collect the names into a 'delete_sources' list, that we use later to clean it up again (either when we're finished with importing or in an error case). Signed-off-by: Dominik Csapak <d.csa...@proxmox.com> --- changes from v1: * put extraction into branch for managed volids * adapt to new module location * add checks for the impor storage if it support 'images' (otherwise we cannot extract there) * add cleanup to other 'create_disks' method PVE/API2/Qemu.pm | 44 ++++++++++++++++++++++++++++++--------- PVE/QemuServer.pm | 5 ++++- PVE/QemuServer/Helpers.pm | 10 +++++++++ 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 2a349c8c..d32967dc 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -24,6 +24,7 @@ use PVE::JSONSchema qw(get_standard_option); use PVE::RESTHandler; use PVE::ReplicationConfig; use PVE::GuestHelpers qw(assert_tag_permissions); +use PVE::GuestImport; use PVE::QemuConfig; use PVE::QemuServer; use PVE::QemuServer::Cloudinit; @@ -159,10 +160,19 @@ my $check_storage_access = sub { if (my $src_image = $drive->{'import-from'}) { my $src_vmid; - if (PVE::Storage::parse_volume_id($src_image, 1)) { # PVE-managed volume - (my $vtype, undef, $src_vmid) = PVE::Storage::parse_volname($storecfg, $src_image); - raise_param_exc({ $ds => "$src_image has wrong type '$vtype' - not an image" }) - if $vtype ne 'images'; + if (my ($storeid, $volname) = PVE::Storage::parse_volume_id($src_image, 1)) { # PVE-managed volume + my $scfg = PVE::Storage::storage_config($storecfg, $storeid); + my $plugin = PVE::Storage::Plugin->lookup($scfg->{type}); + (my $vtype, undef, $src_vmid) = $plugin->parse_volname($volname); + + raise_param_exc({ $ds => "$src_image has wrong type '$vtype' - needs to be 'images' or 'import'" }) + if $vtype ne 'images' && $vtype ne 'import'; + + if (PVE::GuestImport::copy_needs_extraction($src_image)) { + raise_param_exc({ $ds => "$src_image is not on an storage with 'images' content type."}) + if !$scfg->{content}->{images}; + $rpcenv->check($authuser, "/storage/$storeid", ['Datastore.AllocateSpace']); + } } if ($src_vmid) { # might be actively used by VM and will be copied via clone_disk() @@ -335,6 +345,7 @@ my sub create_disks : prototype($$$$$$$$$$) { my $res = {}; my $live_import_mapping = {}; + my $delete_sources = []; my $code = sub { my ($ds, $disk) = @_; @@ -392,6 +403,12 @@ my sub create_disks : prototype($$$$$$$$$$) { $needs_creation = $live_import; if (PVE::Storage::parse_volume_id($source, 1)) { # PVE-managed volume + if (PVE::GuestImport::copy_needs_extraction($source)) { # needs extraction beforehand + print "extracting $source\n"; + $source = PVE::GuestImport::extract_disk_from_import_file($source, $vmid); + print "finished extracting to $source\n"; + push @$delete_sources, $source; + } if ($live_import && $ds ne 'efidisk0') { my $path = PVE::Storage::path($storecfg, $source) or die "failed to get a path for '$source'\n"; @@ -514,13 +531,14 @@ my sub create_disks : prototype($$$$$$$$$$) { eval { PVE::Storage::vdisk_free($storecfg, $volid); }; warn $@ if $@; } + PVE::QemuServer::Helpers::cleanup_extracted_images($delete_sources); die $err; } # don't return empty import mappings $live_import_mapping = undef if !%$live_import_mapping; - return ($vollist, $res, $live_import_mapping); + return ($vollist, $res, $live_import_mapping, $delete_sources); }; my $check_cpu_model_access = sub { @@ -1079,6 +1097,7 @@ __PACKAGE__->register_method({ my $createfn = sub { my $live_import_mapping = {}; + my $delete_sources = []; # ensure no old replication state are exists PVE::ReplicationState::delete_guest_states($vmid); @@ -1096,7 +1115,7 @@ __PACKAGE__->register_method({ my $vollist = []; eval { - ($vollist, my $created_opts, $live_import_mapping) = create_disks( + ($vollist, my $created_opts, $live_import_mapping, $delete_sources) = create_disks( $rpcenv, $authuser, $conf, @@ -1149,6 +1168,7 @@ __PACKAGE__->register_method({ eval { PVE::Storage::vdisk_free($storecfg, $volid); }; warn $@ if $@; } + PVE::QemuServer::Helpers::cleanup_extracted_images($delete_sources); die "$emsg $err"; } @@ -1165,7 +1185,7 @@ __PACKAGE__->register_method({ warn $@ if $@; return; } else { - return $live_import_mapping; + return ($live_import_mapping, $delete_sources); } }; @@ -1192,7 +1212,7 @@ __PACKAGE__->register_method({ $code = sub { # If a live import was requested the create function returns # the mapping for the startup. - my $live_import_mapping = eval { $createfn->() }; + my ($live_import_mapping, $delete_sources) = eval { $createfn->() }; if (my $err = $@) { eval { my $conffile = PVE::QemuConfig->config_file($vmid); @@ -1214,7 +1234,10 @@ __PACKAGE__->register_method({ $vmid, $conf, $import_options, + $delete_sources, ); + } else { + PVE::QemuServer::Helpers::cleanup_extracted_images($delete_sources); } }; } @@ -1939,8 +1962,7 @@ my $update_vm_api = sub { assert_scsi_feature_compatibility($opt, $conf, $storecfg, $param->{$opt}) if $opt =~ m/^scsi\d+$/; - - my (undef, $created_opts) = create_disks( + my (undef, $created_opts, undef, $delete_sources) = create_disks( $rpcenv, $authuser, $conf, @@ -1954,6 +1976,8 @@ my $update_vm_api = sub { ); $conf->{pending}->{$_} = $created_opts->{$_} for keys $created_opts->%*; + PVE::QemuServer::Helpers::cleanup_extracted_images($delete_sources); + # default legacy boot order implies all cdroms anyway if (@bootorder) { # append new CD drives to bootorder to mark them bootable diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 28e630d3..f842451e 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -7303,7 +7303,7 @@ sub pbs_live_restore { # therefore already handled in the `$create_disks()` call happening in the # `create` api call sub live_import_from_files { - my ($mapping, $vmid, $conf, $restore_options) = @_; + my ($mapping, $vmid, $conf, $restore_options, $delete_sources) = @_; my $live_restore_backing = {}; for my $dev (keys %$mapping) { @@ -7364,6 +7364,8 @@ sub live_import_from_files { mon_cmd($vmid, 'blockdev-del', 'node-name' => "drive-$ds-restore"); } + PVE::QemuServer::Helpers::cleanup_extracted_images($delete_sources); + close($qmeventd_fd); }; @@ -7372,6 +7374,7 @@ sub live_import_from_files { if ($err) { warn "An error occurred during live-restore: $err\n"; _do_vm_stop($storecfg, $vmid, 1, 1, 10, 0, 1); + PVE::QemuServer::Helpers::cleanup_extracted_images($delete_sources); die "live-restore failed\n"; } diff --git a/PVE/QemuServer/Helpers.pm b/PVE/QemuServer/Helpers.pm index 0afb6317..f6bec1d4 100644 --- a/PVE/QemuServer/Helpers.pm +++ b/PVE/QemuServer/Helpers.pm @@ -6,6 +6,7 @@ use warnings; use File::stat; use JSON; +use PVE::GuestImport; use PVE::INotify; use PVE::ProcFSTools; @@ -225,4 +226,13 @@ sub windows_version { return $winversion; } +sub cleanup_extracted_images { + my ($delete_sources) = @_; + + for my $source (@$delete_sources) { + eval { PVE::GuestImport::cleanup_extracted_image($source) }; + warn $@ if $@; + } +} + 1; -- 2.39.2 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel