From: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>
To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>
Subject: Re: [pve-devel] [PATCH storage 2/9] plugin: dir: implement import content type
Date: Wed, 17 Apr 2024 14:46:03 +0200 [thread overview]
Message-ID: <1713348628.veapr19pyr.astroid@yuna.none> (raw)
In-Reply-To: <20240416131909.2867605-3-d.csapak@proxmox.com>
On April 16, 2024 3:18 pm, Dominik Csapak wrote:
> in DirPlugin and not Plugin (because of cyclic dependency of
> Plugin -> OVF -> Storage -> Plugin otherwise)
>
> only ovf is currently supported (though ova will be shown in import
> listing), expects the files to not be in a subdir, and adjacent to the
> ovf file.
>
> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
> ---
> src/PVE/Storage.pm | 8 ++++++-
> src/PVE/Storage/DirPlugin.pm | 37 +++++++++++++++++++++++++++++-
> src/PVE/Storage/OVF.pm | 2 ++
> src/PVE/Storage/Plugin.pm | 18 ++++++++++++++-
> src/test/parse_volname_test.pm | 13 +++++++++++
> src/test/path_to_volume_id_test.pm | 16 +++++++++++++
> 6 files changed, 91 insertions(+), 3 deletions(-)
>
> diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm
> index 40314a8..f8ea93d 100755
> --- a/src/PVE/Storage.pm
> +++ b/src/PVE/Storage.pm
> @@ -114,6 +114,8 @@ our $VZTMPL_EXT_RE_1 = qr/\.tar\.(gz|xz|zst)/i;
>
> our $BACKUP_EXT_RE_2 = qr/\.(tgz|(?:tar|vma)(?:\.(${\PVE::Storage::Plugin::COMPRESSOR_RE}))?)/;
>
> +our $IMPORT_EXT_RE_1 = qr/\.(ov[af])/;
> +
> # FIXME remove with PVE 8.0, add versioned breaks for pve-manager
> our $vztmpl_extension_re = $VZTMPL_EXT_RE_1;
>
> @@ -612,6 +614,7 @@ sub path_to_volume_id {
> my $backupdir = $plugin->get_subdir($scfg, 'backup');
> my $privatedir = $plugin->get_subdir($scfg, 'rootdir');
> my $snippetsdir = $plugin->get_subdir($scfg, 'snippets');
> + my $importdir = $plugin->get_subdir($scfg, 'import');
>
> if ($path =~ m!^$imagedir/(\d+)/([^/\s]+)$!) {
> my $vmid = $1;
> @@ -640,6 +643,9 @@ sub path_to_volume_id {
> } elsif ($path =~ m!^$snippetsdir/([^/]+)$!) {
> my $name = $1;
> return ('snippets', "$sid:snippets/$name");
> + } elsif ($path =~ m!^$importdir/([^/]+${IMPORT_EXT_RE_1})$!) {
> + my $name = $1;
> + return ('import', "$sid:import/$name");
> }
> }
>
> @@ -2170,7 +2176,7 @@ sub normalize_content_filename {
> # If a storage provides an 'import' content type, it should be able to provide
> # an object implementing the import information interface.
> sub get_import_metadata {
> - my ($cfg, $volid) = @_;
> + my ($cfg, $volid, $target) = @_;
>
> my ($storeid, $volname) = parse_volume_id($volid);
>
> diff --git a/src/PVE/Storage/DirPlugin.pm b/src/PVE/Storage/DirPlugin.pm
> index 2efa8d5..4dc7708 100644
> --- a/src/PVE/Storage/DirPlugin.pm
> +++ b/src/PVE/Storage/DirPlugin.pm
> @@ -10,6 +10,7 @@ use IO::File;
> use POSIX;
>
> use PVE::Storage::Plugin;
> +use PVE::Storage::OVF;
> use PVE::JSONSchema qw(get_standard_option);
>
> use base qw(PVE::Storage::Plugin);
> @@ -22,7 +23,7 @@ sub type {
>
> sub plugindata {
> return {
> - content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1, backup => 1, snippets => 1, none => 1 },
> + content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1, backup => 1, snippets => 1, none => 1, import => 1 },
> { images => 1, rootdir => 1 }],
> format => [ { raw => 1, qcow2 => 1, vmdk => 1, subvol => 1 } , 'raw' ],
> };
> @@ -247,4 +248,38 @@ sub check_config {
> return $opts;
> }
>
> +sub get_import_metadata {
> + my ($class, $scfg, $volname, $storeid, $target) = @_;
> +
> + if ($volname !~ m!^([^/]+)/.*${PVE::Storage::IMPORT_EXT_RE_1}$!) {
> + die "volume '$volname' does not look like an importable vm config\n";
> + }
shouldn't this happen in parse_volname? or rather, why is this different
than the code there?
> +
> + my $path = $class->path($scfg, $volname, $storeid, undef);
> +
> + # NOTE: all types must be added to the return schema of the import-metadata API endpoint
> + my $warnings = [];
> +
> + my $res = PVE::Storage::OVF::parse_ovf($path, $isOva);
nit: $isOva doesn't yet exist in this patch, neither as variable here,
nor as parameter in parse_ovf ;)
> + my $disks = {};
> + for my $disk ($res->{disks}->@*) {
> + my $id = $disk->{disk_address};
> + my $size = $disk->{virtual_size};
> + my $path = $disk->{relative_path};
see below
> + $disks->{$id} = {
> + volid => "$storeid:import/$path",
> + defined($size) ? (size => $size) : (),
> + };
> + }
> +
> + return {
> + type => 'vm',
> + source => $volname,
> + 'create-args' => $res->{qm},
> + 'disks' => $disks,
> + warnings => $warnings,
> + net => [],
> + };
> +}
> +
> 1;
> diff --git a/src/PVE/Storage/OVF.pm b/src/PVE/Storage/OVF.pm
> index 90ca453..4a322b9 100644
> --- a/src/PVE/Storage/OVF.pm
> +++ b/src/PVE/Storage/OVF.pm
> @@ -222,6 +222,7 @@ ovf:Item[rasd:InstanceID='%s']/rasd:ResourceType", $controller_id);
> }
>
> ($backing_file_path) = $backing_file_path =~ m|^(/.*)|; # untaint
> + ($filepath) = $filepath =~ m|^(.*)|; # untaint
nit: that's a weird untaint ;) maybe add the `$` at least to prevent
future bugs?
>
> my $virtual_size = PVE::Storage::file_size_info($backing_file_path);
> die "error parsing $backing_file_path, cannot determine file size\n"
> @@ -231,6 +232,7 @@ ovf:Item[rasd:InstanceID='%s']/rasd:ResourceType", $controller_id);
> disk_address => $pve_disk_address,
> backing_file => $backing_file_path,
> virtual_size => $virtual_size
> + relative_path => $filepath,
nothing actually ensures $filepath doesn't contain an absolute path
(that is also valid when concatenating it with the ovs dir).. right now
it would then choke on the double `//`, but I haven't tried all the
wonky stuff you could possibly do..
wouldn't it be more safe to transform back from $backing_file_path to
ensure there is no mismatch/potential for confusion? also, I am not sure
if this wouldn't allow injecting stuff (if $filepath contains weird
characters, or its resolved variant $backing_file_path does) - should we
limit ourselves to a certain character set that we know to be okay as
part of a volid?
I have to admit I didn't follow the XML DTD stuff in detail (it's rather
convoluted), so maybe parts of this are handled there, but I am not sure
I would want to rely on that in any case ;)
> };
> push @disks, $pve_disk;
>
> diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm
> index 22a9729..deaf8b2 100644
> --- a/src/PVE/Storage/Plugin.pm
> +++ b/src/PVE/Storage/Plugin.pm
> @@ -654,6 +654,10 @@ sub parse_volname {
> return ('backup', $fn);
> } elsif ($volname =~ m!^snippets/([^/]+)$!) {
> return ('snippets', $1);
> + } elsif ($volname =~ m!^import/([^/]+$PVE::Storage::IMPORT_EXT_RE_1)$!) {
> + return ('import', $1);
> + } elsif ($volname =~ m!^import/([^/]+\.(raw|vmdk|qcow2))$!) {
> + return ('images', $1, 0, undef, undef, undef, $2);
> }
>
> die "unable to parse directory volume name '$volname'\n";
> @@ -666,6 +670,7 @@ my $vtype_subdirs = {
> vztmpl => 'template/cache',
> backup => 'dump',
> snippets => 'snippets',
> + import => 'import',
> };
>
> sub get_vtype_subdirs {
> @@ -691,6 +696,11 @@ sub filesystem_path {
> my ($vtype, $name, $vmid, undef, undef, $isBase, $format) =
> $class->parse_volname($volname);
>
> + if (defined($vmid) && $vmid == 0) {
> + # import volumes?
> + $vtype = 'import';
> + }
> +
> # Note: qcow2/qed has internal snapshot, so path is always
> # the same (with or without snapshot => same file).
> die "can't snapshot this image format\n"
> @@ -1227,7 +1237,7 @@ sub list_images {
> return $res;
> }
>
> -# list templates ($tt = <iso|vztmpl|backup|snippets>)
> +# list templates ($tt = <iso|vztmpl|backup|snippets|import>)
> my $get_subdir_files = sub {
> my ($sid, $path, $tt, $vmid) = @_;
>
> @@ -1283,6 +1293,10 @@ my $get_subdir_files = sub {
> volid => "$sid:snippets/". basename($fn),
> format => 'snippet',
> };
> + } elsif ($tt eq 'import') {
> + next if $fn !~ m!/([^/]+$PVE::Storage::IMPORT_EXT_RE_1)$!i;
> +
> + $info = { volid => "$sid:import/$1", format => "$2" };
> }
>
> $info->{size} = $st->size;
> @@ -1317,6 +1331,8 @@ sub list_volumes {
> $data = $get_subdir_files->($storeid, $path, 'backup', $vmid);
> } elsif ($type eq 'snippets') {
> $data = $get_subdir_files->($storeid, $path, 'snippets');
> + } elsif ($type eq 'import') {
> + $data = $get_subdir_files->($storeid, $path, 'import');
> }
> }
>
> diff --git a/src/test/parse_volname_test.pm b/src/test/parse_volname_test.pm
> index d6ac885..59819f0 100644
> --- a/src/test/parse_volname_test.pm
> +++ b/src/test/parse_volname_test.pm
> @@ -81,6 +81,19 @@ my $tests = [
> expected => ['snippets', 'hookscript.pl'],
> },
> #
> + #
> + #
> + {
> + description => "Import, ova",
> + volname => 'import/import.ova',
> + expected => ['import', 'import.ova'],
> + },
> + {
> + description => "Import, ovf",
> + volname => 'import/import.ovf',
> + expected => ['import', 'import.ovf'],
> + },
> + #
> # failed matches
> #
> {
> diff --git a/src/test/path_to_volume_id_test.pm b/src/test/path_to_volume_id_test.pm
> index 8149c88..8bc1bf8 100644
> --- a/src/test/path_to_volume_id_test.pm
> +++ b/src/test/path_to_volume_id_test.pm
> @@ -174,6 +174,22 @@ my @tests = (
> 'local:vztmpl/debian-10.0-standard_10.0-1_amd64.tar.xz',
> ],
> },
> + {
> + description => 'Import, ova',
> + volname => "$storage_dir/import/import.ova",
> + expected => [
> + 'import',
> + 'local:import/import.ova',
> + ],
> + },
> + {
> + description => 'Import, ovf',
> + volname => "$storage_dir/import/import.ovf",
> + expected => [
> + 'import',
> + 'local:import/import.ovf',
> + ],
> + },
>
> # no matches, path or files with failures
> {
> --
> 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
next prev parent reply other threads:[~2024-04-17 12:46 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-16 13:18 [pve-devel] [PATCH storage/qemu-server/pve-manager] implement ova/ovf import for directory type storages Dominik Csapak
2024-04-16 13:18 ` [pve-devel] [PATCH storage 1/9] copy OVF.pm from qemu-server Dominik Csapak
2024-04-16 15:02 ` Thomas Lamprecht
2024-04-17 9:19 ` Fiona Ebner
2024-04-17 9:26 ` Thomas Lamprecht
2024-04-16 13:18 ` [pve-devel] [PATCH storage 2/9] plugin: dir: implement import content type Dominik Csapak
2024-04-17 10:07 ` Fiona Ebner
2024-04-17 10:07 ` Fiona Ebner
2024-04-17 13:13 ` Dominik Csapak
2024-04-17 12:46 ` Fabian Grünbichler [this message]
2024-04-16 13:18 ` [pve-devel] [PATCH storage 3/9] plugin: dir: handle ova files for import Dominik Csapak
2024-04-17 10:52 ` Fiona Ebner
2024-04-17 13:07 ` Dominik Csapak
2024-04-17 13:39 ` Fabian Grünbichler
2024-04-18 7:22 ` Fiona Ebner
2024-04-18 7:25 ` Fiona Ebner
2024-04-18 8:55 ` Fabian Grünbichler
2024-04-17 12:45 ` Fabian Grünbichler
2024-04-17 13:10 ` Dominik Csapak
2024-04-17 13:52 ` Fabian Grünbichler
2024-04-17 14:07 ` Dominik Csapak
2024-04-18 6:46 ` Fabian Grünbichler
2024-04-16 13:18 ` [pve-devel] [PATCH storage 4/9] ovf: implement parsing the ostype Dominik Csapak
2024-04-17 11:32 ` Fiona Ebner
2024-04-17 13:14 ` Dominik Csapak
2024-04-18 7:31 ` Fiona Ebner
2024-04-16 13:18 ` [pve-devel] [PATCH storage 5/9] ovf: implement parsing out firmware type Dominik Csapak
2024-04-17 11:43 ` Fiona Ebner
2024-04-16 13:18 ` [pve-devel] [PATCH storage 6/9] ovf: implement rudimentary boot order Dominik Csapak
2024-04-17 11:54 ` Fiona Ebner
2024-04-17 13:15 ` Dominik Csapak
2024-04-16 13:19 ` [pve-devel] [PATCH storage 7/9] ovf: implement parsing nics Dominik Csapak
2024-04-17 12:09 ` Fiona Ebner
2024-04-17 13:16 ` Dominik Csapak
2024-04-18 8:22 ` Fiona Ebner
2024-04-16 13:19 ` [pve-devel] [PATCH storage 8/9] api: allow ova upload/download Dominik Csapak
2024-04-18 8:05 ` Fiona Ebner
2024-04-16 13:19 ` [pve-devel] [PATCH storage 9/9] plugin: enable import for nfs/btfs/cifs/cephfs Dominik Csapak
2024-04-18 8:43 ` Fiona Ebner
2024-04-16 13:19 ` [pve-devel] [PATCH qemu-server 1/3] api: delete unused OVF.pm Dominik Csapak
2024-04-18 8:52 ` Fiona Ebner
2024-04-18 8:57 ` Dominik Csapak
2024-04-18 9:03 ` Fiona Ebner
2024-04-16 13:19 ` [pve-devel] [PATCH qemu-server 2/3] use OVF from Storage Dominik Csapak
2024-04-18 9:07 ` Fiona Ebner
2024-04-16 13:19 ` [pve-devel] [PATCH qemu-server 3/3] api: create: implement extracting disks when needed for import-from Dominik Csapak
2024-04-18 9:41 ` Fiona Ebner
2024-04-18 9:48 ` Dominik Csapak
2024-04-18 9:55 ` Fiona Ebner
2024-04-18 9:58 ` Dominik Csapak
2024-04-18 10:01 ` Fiona Ebner
2024-04-16 13:19 ` [pve-devel] [PATCH manager 1/4] ui: fix special 'import' icon for non-esxi storages Dominik Csapak
2024-04-16 13:19 ` [pve-devel] [PATCH manager 2/4] ui: guest import: add ova-needs-extracting warning text Dominik Csapak
2024-04-16 13:19 ` [pve-devel] [PATCH manager 3/4] ui: enable import content type for relevant storages Dominik Csapak
2024-04-16 13:19 ` [pve-devel] [PATCH manager 4/4] ui: enable upload/download buttons for 'import' type storages Dominik Csapak
2024-04-17 12:37 ` Fabian Grünbichler
2024-04-18 11:20 ` Fiona Ebner
2024-04-18 11:23 ` Dominik Csapak
2024-04-18 11:26 ` Fiona Ebner
2024-04-17 13:11 ` [pve-devel] [PATCH storage/qemu-server/pve-manager] implement ova/ovf import for directory " Fabian Grünbichler
2024-04-17 13:19 ` Dominik Csapak
2024-04-18 6:40 ` Fabian Grünbichler
2024-04-18 9:27 ` Dominik Csapak
2024-04-18 10:35 ` Fiona Ebner
2024-04-18 11:10 ` Dominik Csapak
2024-04-18 11:13 ` Fiona Ebner
2024-04-18 11:17 ` Fabian Grünbichler
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1713348628.veapr19pyr.astroid@yuna.none \
--to=f.gruenbichler@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.