On April 29, 2024 1:21 pm, Dominik Csapak wrote:
> 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>
> ---
>  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);

please use PVE::Storage instead!

> +
> +             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)) {

like noted in the patch introducing that helper, it could just be
inlined here..

> +                 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 = [];

we already have a list of created volumes here that are cleaned up on
error ($vollist), so this is just to also clean them up after importing
if that worked? and then, it's basically just for live importing (since
for non-live imports, we can just free the volume right after the import
was successful?)? but live imports already have their own hash anyway
($live_import_mapping), we could just annotate the volume there?

>  
>      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";

this is a bit hard to follow, it might be more readable to do

my $extracted_volid = ..;
$source = $extracted_volid;

even if the end result is the same, it makes it much more explicit what
is happening here with $source?

> +                     push @$delete_sources, $source;

this could just push to $vollist I think..

> +                 }
>                   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);

then this would not be needed, since we cleanup all the freshly
allocated volumes above anyway..

>       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);

this can then be dropped as well..

>  };
>  
>  my $check_cpu_model_access = sub {
> @@ -1079,6 +1097,7 @@ __PACKAGE__->register_method({
>  
>       my $createfn = sub {
>           my $live_import_mapping = {};
> +         my $delete_sources = [];

so can this

>  
>           # 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(

and this

>                       $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);

and this :)

>                   die "$emsg $err";
>               }
>  
> @@ -1165,7 +1185,7 @@ __PACKAGE__->register_method({
>               warn $@ if $@;
>               return;
>           } else {
> -             return $live_import_mapping;
> +             return ($live_import_mapping, $delete_sources);

as well as this

>           }
>       };
>  
> @@ -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->() };

this

>               if (my $err = $@) {
>                   eval {
>                       my $conffile = PVE::QemuConfig->config_file($vmid);
> @@ -1214,7 +1234,10 @@ __PACKAGE__->register_method({
>                       $vmid,
>                       $conf,
>                       $import_options,
> +                     $delete_sources,

this

>                   );
> +             } else {
> +                 
> PVE::QemuServer::Helpers::cleanup_extracted_images($delete_sources);

and this?

>               }
>           };
>       }
> @@ -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(

not needed either

>                       $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);

same here

> +
>                   # 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 82e7d6a6..4bd0ae85 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) = @_;

here

>  
>      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);

and this could then just free based on a flag in the mapping..

> +
>       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);

and here as well..

>       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 $@;
> +    }
> +}
> +

and this can then be dropped, since it's just a wrapper around a helper
that is itself just a wrapper of vdisk_free..

>  1;
> -- 
> 2.39.2
> 
> 
> 
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
> 
> 
> 


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to