[pve-devel] [PATCH qemu-server v3] Prepare API for import GUI
Dominic Jäger
d.jaeger at proxmox.com
Fri Dec 18 12:49:28 CET 2020
Move existing import functionality to the API so that it is available for the
GUI.
Signed-off-by: Dominic Jäger <d.jaeger at proxmox.com>
---
I haven't checked everything (e.g. permissions, code style) yet, but
1. a large part of intermediate bloat is away (some may be left)
2. it's rebased
3. so clicking through the GUI works (again)
Therefore I wanted to send a short update before going on holiday.
PVE/API2/Qemu.pm | 258 ++++++++++++++++++++++++++++++++++-
PVE/CLI/qm.pm | 127 +++--------------
PVE/QemuServer.pm | 18 ++-
PVE/QemuServer/Drive.pm | 21 +++
PVE/QemuServer/ImportDisk.pm | 85 ------------
PVE/QemuServer/Makefile | 1 -
PVE/QemuServer/OVF.pm | 10 +-
7 files changed, 319 insertions(+), 201 deletions(-)
delete mode 100755 PVE/QemuServer/ImportDisk.pm
diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index e2d2d67..e6856e6 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -45,7 +45,6 @@ BEGIN {
}
}
-use Data::Dumper; # fixme: remove
use base qw(PVE::RESTHandler);
@@ -173,6 +172,28 @@ my $create_disks = sub {
push @$vollist, $volid;
delete $disk->{format}; # no longer needed
$res->{$ds} = PVE::QemuServer::print_drive($disk);
+ } elsif ($disk->{importsource}) {
+ # must be before $NEW_DISK_RE because $NEW_DISK_RE is matched in imports
+ # because the "magic" number of the volid is irrelevant and arbitrarily set to 0 so the API allows it
+ my $volid_as_path = eval { # Nonempty iff $original_source is a volid
+ PVE::Storage::path($storecfg, $disk->{importsource});
+ };
+ my $source_as_path = $volid_as_path || $disk->{importsource} ;
+ my $volid = $PVE::API2::Qemu::import_disk->({
+ vmid => $vmid,
+ original_source => $disk->{importsource},
+ device_options => "discard=on",
+ storage => (split(':', $disk->{file}))[0],
+ source_as_path => $source_as_path,
+ format => $disk->{format},
+ skiplock => 1,
+ }
+ );
+
+ delete $disk->{importsource};
+ $disk->{file} = $volid;
+ push @$vollist, $volid;
+ $res->{$ds} = PVE::QemuServer::print_drive($disk);
} elsif ($volid =~ $NEW_DISK_RE) {
my ($storeid, $size) = ($2 || $default_storage, $3);
die "no storage ID specified (and no default storage)\n" if !$storeid;
@@ -1281,6 +1302,19 @@ my $update_vm_api = sub {
if defined($conf->{pending}->{$opt});
&$create_disks($rpcenv, $authuser, $conf->{pending}, $arch, $storecfg, $vmid, undef, {$opt => $param->{$opt}});
+ } elsif ($param->{$opt} =~ m/importsource/) {
+ my $disk = $param->{$opt};
+ $disk =~ s/importsource=([^,]+),?//;
+ my $path = $1;
+ $disk =~ m/^(.+):0/;
+ my $storage = $1;
+ my $volid = $PVE::API2::Qemu::import_disk->({
+ vmid => $vmid,
+ source_as_path => $path,
+ storage => $storage,
+ });
+
+ $conf->{pending}->{$opt} = $volid;
} elsif ($opt =~ m/^serial\d+/) {
if ((!defined($conf->{$opt}) || $conf->{$opt} eq 'socket') && $param->{$opt} eq 'socket') {
$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']);
@@ -4320,4 +4354,226 @@ __PACKAGE__->register_method({
return PVE::QemuServer::Cloudinit::dump_cloudinit_config($conf, $param->{vmid}, $param->{type});
}});
+# TODO Make locally scoped when importovf is moved from qm to API / this package
+#
+# 2-step process:
+# 1. convert is qemu-img convert
+# 2. attach is update_vm_api
+#
+# vmid ... target VM ID
+# source_as_path ... absolute path of the source image (volid must be converted before)
+# device ... device/drive where the image will be attached (ide0, sata2, ...)
+# device_options ... options for attaching the device (discard=on,cache=unsafe, ...)
+# storage ... target storage for the disk image
+# format ... target format for the disk image
+# skiplock ... if skiploc during attach/upate_vm_api,
+our $import_disk = sub {
+ my ($param) = @_;
+ my $vm_conf = PVE::QemuConfig->load_config($param->{vmid});
+ my $store_conf = PVE::Storage::config();
+ PVE::QemuConfig->check_lock($vm_conf) if !$param->{skiplock};
+ if (!$param->{storage}) {
+ die "It is necessary to pass the storage parameter";
+ }
+ if ($param->{device} && $vm_conf->{$param->{device}}) {
+ die "Could not import because device $param->{device} is already in ".
+ "use in VM $param->{vmid}. Choose a different device!\n";
+ }
+ if ($param->{digest} && $param->{digest} ne $vm_conf->{digest}) {
+ die "VM $param->{vmid} config checksum missmatch (file change by other user?)\n";
+ }
+
+ my $msg = $param->{device} ? "to $param->{device} on" : 'as unused disk to';
+ print "Importing disk '$param->{source_as_path}' $msg VM $param->{vmid}...\n";
+
+ my $src_size = PVE::Storage::file_size_info($param->{source_as_path});
+ if (!defined($src_size)) {
+ die "Could not get file size of $param->{source_as_path}";
+ } elsif (!$src_size) {
+ die "Size of file $param->{source_as_path} is 0";
+ } elsif ($src_size==1) {
+ die "Cannot import directory";
+ }
+
+ my $dst_format = PVE::QemuServer::resolve_dst_disk_format(
+ $store_conf, $param->{storage}, undef, $param->{format});
+ my $dst_volid = PVE::Storage::vdisk_alloc($store_conf, $param->{storage},
+ $param->{vmid}, $dst_format, undef, $src_size / 1024);
+
+ eval {
+ local $SIG{INT} =
+ local $SIG{TERM} =
+ local $SIG{QUIT} =
+ local $SIG{HUP} =
+ local $SIG{PIPE} = sub { die "Interrupted by signal $!\n"; };
+
+ my $zeroinit = PVE::Storage::volume_has_feature($store_conf,
+ 'sparseinit', $dst_volid);
+
+ PVE::Storage::activate_volumes($store_conf, [$dst_volid]);
+ PVE::QemuServer::qemu_img_convert($param->{source_as_path}, $dst_volid,
+ $src_size, undef, $zeroinit);
+ PVE::Storage::deactivate_volumes($store_conf, [$dst_volid]);
+
+ };
+ if (my $err = $@) {
+ eval { PVE::Storage::vdisk_free($store_conf, $dst_volid) };
+ warn "Cleanup of $dst_volid failed: $@ \n" if $@;
+
+ die "Importing disk '$param->{source_as_path}' failed: $err\n" if $err;
+ }
+
+ return $dst_volid;
+};
+
+__PACKAGE__->register_method ({
+ name => 'importdisk',
+ path => '{vmid}/importdisk',
+ method => 'POST',
+ protected => 1, # for worker upid file
+ proxyto => 'node',
+ description => "Import an external disk image into a VM. The image format ".
+ "has to be supported by qemu-img.",
+ permissions => {
+ check => [ 'and',
+ [ 'perm', '/storage/{storage}', ['Datastore.Audit']],
+ [ 'perm', '/storage/{storage}', ['Datastore.Allocate']],
+ [ 'perm', '/storage/{storage}', ['Datastore.AllocateTemplate']],
+ [ 'perm', '/storage/{storage}', ['Datastore.AllocateSpace']],
+ [ 'perm', '/vms/{vmid}', ['VM.Allocate']],
+ [ 'perm', '/vms/{vmid}', ['VM.Config.Disk']],
+ ],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ vmid => get_standard_option('pve-vmid',
+ {completion => \&PVE::QemuServer::complete_vmid}),
+ source => {
+ description => "Disk image to import. Can be a volid ".
+ "(local-lvm:vm-104-disk-0), an image on a PVE storage ".
+ "(local:104/toImport.raw) or (for root only) an absolute ".
+ "path on the server.",
+ type => 'string',
+ },
+ device => {
+ type => 'string',
+ description => "Bus/Device type of the new disk (e.g. 'ide0', ".
+ "'scsi2'). Will add the image as unused disk if omitted.",
+ enum => [PVE::QemuServer::Drive::valid_drive_names()],
+ optional => 1,
+ },
+ device_options => {
+ type => 'string',
+ format => 'drive_options',
+ description => "Options to set for the new disk ".
+ "(e.g. 'discard=on,backup=0')",
+ optional => 1,
+ },
+ storage => get_standard_option('pve-storage-id', {
+ description => "The storage to which the image will be imported to.",
+ completion => \&PVE::QemuServer::complete_storage,
+ }),
+ format => {
+ type => 'string',
+ description => 'Target format.',
+ enum => [ 'raw', 'qcow2', 'vmdk' ],
+ optional => 1,
+ },
+ digest => get_standard_option('pve-config-digest'),
+ skiplock => get_standard_option('skiplock'),
+ },
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
+
+ my $vmid = extract_param($param, 'vmid');
+ my $original_source = extract_param($param, 'source');
+ my $digest = extract_param($param, 'digest');
+ my $device_options = extract_param($param, 'device_options');
+ my $device = extract_param($param, 'device');
+ # importovf holds a lock itself which would make automatically updating
+ # VM configs fail
+ my $skiplock = extract_param($param, 'skiplock');
+ my $storecfg = PVE::Storage::config();
+
+ if ($skiplock && $authuser ne 'root at pam') {
+ raise_perm_exc("Only root may use skiplock.");
+ }
+ if ($original_source eq "") {
+ die "Could not import because source parameter is an empty string!\n";
+ }
+ if ($device && !PVE::QemuServer::is_valid_drivename($device)) {
+ die "Invalid device name: $device!";
+ }
+ if ($device_options && !$device) {
+ die "Cannot use --device_options without specifying --device!"
+ }
+
+ if ($original_source =~ m/^http/) {
+ die "implement me";
+ # my $tmpPath = '/tmp';
+ # PVE::Tools::run_command(['/usr/bin/wget', $original_source, '-P', $tmpPath]);
+ # $original_source =~ m!([^/]+)$!;
+ # my $filename = $tmpPath . '/' . $1;
+ # my $extractDir = $tmpPath .'/' . 'pve_importing';
+ # if ($filename =~ m/.zip$/) {
+ # PVE::Tools::run_command(['/usr/bin/unzip', $filename, '-d', $extractDir], outfunc => sub {
+ # my $line = shift;
+ # if ($line =~ m!\s*extracting:\s*(\S+)\s*$!) {
+ # my $extracted_file = $1;
+ # $original_source = $extracted_file; # only one file for the moment
+ # }
+
+ # });
+ # } else {
+ # die "Can only import .zip files from URLs";
+ # }
+ } else {
+ eval {
+ PVE::Storage::check_volume_access($rpcenv, $authuser, $storecfg,
+ $vmid, $original_source)
+ };
+ raise_perm_exc($@) if $@;
+ }
+
+ # A path is required for $import_disk
+ my $volid_as_path = eval { # Nonempty iff $original_source is a volid
+ PVE::Storage::path($storecfg, $original_source);
+ };
+ my $source_as_path = $volid_as_path || $original_source ;
+ if (!-e $source_as_path) {
+ die "Could not import because source '$original_source' does not exist!\n";
+ }
+
+ my $storeid = extract_param($param, 'storage');
+ my $format = extract_param($param, 'format');
+ my $conf = PVE::QemuConfig->load_config($vmid);
+
+ my $volid = "${storeid}:0";
+ if ($device_options) {
+ $volid .= ",${device_options}";
+ }
+ $volid .= ",importsource=${source_as_path}";
+ if ($device) {
+ $update_vm_api->({
+ node => "dev",
+ vmid => $vmid,
+ $device => $volid,
+ });
+ } else {
+ $device = PVE::QemuConfig->add_unused_volume($conf, $volid);
+ $update_vm_api->({
+ node => "dev",
+ vmid => $vmid,
+ $device => $volid,
+ });
+ }
+ return;
+ }});
+
1;
diff --git a/PVE/CLI/qm.pm b/PVE/CLI/qm.pm
index b9b6051..56e57ea 100755
--- a/PVE/CLI/qm.pm
+++ b/PVE/CLI/qm.pm
@@ -27,11 +27,12 @@ use PVE::Tools qw(extract_param);
use PVE::API2::Qemu::Agent;
use PVE::API2::Qemu;
+use PVE::API2::Nodes;
+use PVE::Storage::Plugin;
use PVE::QemuConfig;
use PVE::QemuServer::Drive;
use PVE::QemuServer::Helpers;
use PVE::QemuServer::Agent qw(agent_available);
-use PVE::QemuServer::ImportDisk;
use PVE::QemuServer::Monitor qw(mon_cmd);
use PVE::QemuServer::OVF;
use PVE::QemuServer;
@@ -440,61 +441,6 @@ __PACKAGE__->register_method ({
return;
}});
-__PACKAGE__->register_method ({
- name => 'importdisk',
- path => 'importdisk',
- method => 'POST',
- description => "Import an external disk image as an unused disk in a VM. The
- image format has to be supported by qemu-img(1).",
- parameters => {
- additionalProperties => 0,
- properties => {
- vmid => get_standard_option('pve-vmid', {completion => \&PVE::QemuServer::complete_vmid}),
- source => {
- description => 'Path to the disk image to import',
- type => 'string',
- optional => 0,
- },
- storage => get_standard_option('pve-storage-id', {
- description => 'Target storage ID',
- completion => \&PVE::QemuServer::complete_storage,
- optional => 0,
- }),
- format => {
- type => 'string',
- description => 'Target format',
- enum => [ 'raw', 'qcow2', 'vmdk' ],
- optional => 1,
- },
- },
- },
- returns => { type => 'null'},
- code => sub {
- my ($param) = @_;
-
- my $vmid = extract_param($param, 'vmid');
- my $source = extract_param($param, 'source');
- my $storeid = extract_param($param, 'storage');
- my $format = extract_param($param, 'format');
-
- my $vm_conf = PVE::QemuConfig->load_config($vmid);
- PVE::QemuConfig->check_lock($vm_conf);
- die "$source: non-existent or non-regular file\n" if (! -f $source);
-
- my $storecfg = PVE::Storage::config();
- PVE::Storage::storage_check_enabled($storecfg, $storeid);
-
- my $target_storage_config = PVE::Storage::storage_config($storecfg, $storeid);
- die "storage $storeid does not support vm images\n"
- if !$target_storage_config->{content}->{images};
-
- print "importing disk '$source' to VM $vmid ...\n";
- my ($drive_id, $volid) = PVE::QemuServer::ImportDisk::do_import($source, $vmid, $storeid, { format => $format });
- print "Successfully imported disk as '$drive_id:$volid'\n";
-
- return;
- }});
-
__PACKAGE__->register_method ({
name => 'terminal',
path => 'terminal',
@@ -612,63 +558,26 @@ __PACKAGE__->register_method ({
my $format = PVE::Tools::extract_param($param, 'format');
my $dryrun = PVE::Tools::extract_param($param, 'dryrun');
- die "$ovf_file: non-existent or non-regular file\n" if (! -f $ovf_file);
- my $storecfg = PVE::Storage::config();
- PVE::Storage::storage_check_enabled($storecfg, $storeid);
-
- my $parsed = PVE::QemuServer::OVF::parse_ovf($ovf_file);
-
- if ($dryrun) {
- print to_json($parsed, { pretty => 1, canonical => 1});
- return;
+ my $all_storages = PVE::Storage::config();
+ PVE::Storage::storage_check_enabled($all_storages, $storeid);
+ if ($format) {
+ my $target_storage_config = PVE::Storage::storage_config($all_storages, $storeid);
+ my (undef, $valid_formats) = PVE::Storage::Plugin::default_format($target_storage_config);
+ if (!grep( /^$format$/, @$valid_formats)) {
+ die "Format $format is not supported in storage $storeid";
+ }
}
- eval { PVE::QemuConfig->create_and_lock_config($vmid) };
- die "Reserving empty config for OVF import to VM $vmid failed: $@" if $@;
-
- my $conf = PVE::QemuConfig->load_config($vmid);
- die "Internal error: Expected 'create' lock in config of VM $vmid!"
- if !PVE::QemuConfig->has_lock($conf, "create");
-
- $conf->{name} = $parsed->{qm}->{name} if defined($parsed->{qm}->{name});
- $conf->{memory} = $parsed->{qm}->{memory} if defined($parsed->{qm}->{memory});
- $conf->{cores} = $parsed->{qm}->{cores} if defined($parsed->{qm}->{cores});
-
- eval {
- # order matters, as do_import() will load_config() internally
- $conf->{vmgenid} = PVE::QemuServer::generate_uuid();
- $conf->{smbios1} = PVE::QemuServer::generate_smbios1_uuid();
- PVE::QemuConfig->write_config($vmid, $conf);
-
- foreach my $disk (@{ $parsed->{disks} }) {
- my ($file, $drive) = ($disk->{backing_file}, $disk->{disk_address});
- PVE::QemuServer::ImportDisk::do_import($file, $vmid, $storeid, {
- drive_name => $drive,
- format => $format,
- skiplock => 1,
- });
+ my $parsed = PVE::API2::Nodes::Nodeinfo->readovf({node=>"dev", manifest=> $ovf_file});
+ delete $parsed->{digest};
+ foreach my $key (keys %$parsed) {
+ if (PVE::QemuServer::is_valid_drivename($key)) {
+ $parsed->{$key} = "$storeid:0,$parsed->{$key}";
}
-
- # reload after disks entries have been created
- $conf = PVE::QemuConfig->load_config($vmid);
- my $devs = PVE::QemuServer::get_default_bootdevices($conf);
- $conf->{boot} = PVE::QemuServer::print_bootorder($devs);
- PVE::QemuConfig->write_config($vmid, $conf);
- };
-
- my $err = $@;
- if ($err) {
- my $skiplock = 1;
- # eval for additional safety in error path
- eval { PVE::QemuServer::destroy_vm($storecfg, $vmid, $skiplock) };
- warn "Could not destroy VM $vmid: $@" if "$@";
- die "import failed - $err";
}
-
- PVE::QemuConfig->remove_lock($vmid, "create");
-
+ my $config = {%$parsed, node=>"dev", vmid=>$vmid};
+ PVE::API2::Qemu->create_vm($config);
return;
-
}
});
@@ -979,7 +888,7 @@ our $cmddef = {
terminal => [ __PACKAGE__, 'terminal', ['vmid']],
- importdisk => [ __PACKAGE__, 'importdisk', ['vmid', 'source', 'storage']],
+ importdisk => [ "PVE::API2::Qemu", 'importdisk', ['vmid', 'source', 'storage'], { node => $nodename }],
importovf => [ __PACKAGE__, 'importovf', ['vmid', 'manifest', 'storage']],
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 43b11c3..02202b4 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -998,6 +998,22 @@ sub verify_volume_id_or_qm_path {
return $volid;
}
+PVE::JSONSchema::register_format('pve-volume-id-or-absolute-path', \&verify_volume_id_or_absolute_path);
+sub verify_volume_id_or_absolute_path {
+ my ($volid, $noerr) = @_;
+
+ if ($volid =~ m|^/|) {
+ return $volid;
+ }
+
+ $volid = eval { PVE::JSONSchema::check_format('pve-volume-id', $volid, '') };
+ if ($@) {
+ return undef if $noerr;
+ die $@;
+ }
+ return $volid;
+}
+
my $usb_fmt = {
host => {
default_key => 1,
@@ -6658,7 +6674,7 @@ sub qemu_img_convert {
$src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
$src_is_iscsi = ($src_path =~ m|^iscsi://|);
$cachemode = 'none' if $src_scfg->{type} eq 'zfspool';
- } elsif (-f $src_volid) {
+ } elsif (-f $src_volid || -b _) { # -b for LVM images for example
$src_path = $src_volid;
if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
$src_format = $1;
diff --git a/PVE/QemuServer/Drive.pm b/PVE/QemuServer/Drive.pm
index d560937..5850e92 100644
--- a/PVE/QemuServer/Drive.pm
+++ b/PVE/QemuServer/Drive.pm
@@ -145,6 +145,13 @@ my %drivedesc_base = (
verbose_description => "Mark this locally-managed volume as available on all nodes.\n\nWARNING: This option does not share the volume automatically, it assumes it is shared already!",
optional => 1,
default => 0,
+ },
+ importsource => {
+ type => 'string',
+ format => 'pve-volume-id-or-absolute-path',
+ format_description => 'Absolute path or volid',
+ description => 'Source to import the disk',
+ optional => 1,
}
);
@@ -308,6 +315,19 @@ my $alldrive_fmt = {
%wwn_fmt,
};
+my %optional_file_drivedesc_base = %drivedesc_base;
+$optional_file_drivedesc_base{file}{optional} = 1;
+my $drive_options_fmt = {
+ %optional_file_drivedesc_base,
+ %iothread_fmt,
+ %model_fmt,
+ %queues_fmt,
+ %scsiblock_fmt,
+ %ssd_fmt,
+ %wwn_fmt,
+};
+PVE::JSONSchema::register_format('drive_options', $drive_options_fmt);
+
my $efidisk_fmt = {
volume => { alias => 'file' },
file => {
@@ -435,6 +455,7 @@ sub parse_drive {
warn "invalid drive key: $key\n";
return;
}
+ use Data::Dumper;
my $desc = $drivedesc_hash->{$key}->{format};
my $res = eval { PVE::JSONSchema::parse_property_string($desc, $data) };
diff --git a/PVE/QemuServer/ImportDisk.pm b/PVE/QemuServer/ImportDisk.pm
deleted file mode 100755
index 51ad52e..0000000
--- a/PVE/QemuServer/ImportDisk.pm
+++ /dev/null
@@ -1,85 +0,0 @@
-package PVE::QemuServer::ImportDisk;
-
-use strict;
-use warnings;
-
-use PVE::Storage;
-use PVE::QemuServer;
-use PVE::Tools qw(run_command extract_param);
-
-# imports an external disk image to an existing VM
-# and creates by default a drive entry unused[n] pointing to the created volume
-# $params->{drive_name} may be used to specify ide0, scsi1, etc ...
-# $params->{format} may be used to specify qcow2, raw, etc ...
-sub do_import {
- my ($src_path, $vmid, $storage_id, $params) = @_;
-
- my $drive_name = extract_param($params, 'drive_name');
- my $format = extract_param($params, 'format');
- if ($drive_name && !(PVE::QemuServer::is_valid_drivename($drive_name))) {
- die "invalid drive name: $drive_name\n";
- }
-
- # get the needed size from source disk
- my $src_size = PVE::Storage::file_size_info($src_path);
-
- # get target format, target image's path, and whether it's possible to sparseinit
- my $storecfg = PVE::Storage::config();
- my $dst_format = PVE::QemuServer::resolve_dst_disk_format($storecfg, $storage_id, undef, $format);
-
- my $dst_volid = PVE::Storage::vdisk_alloc($storecfg, $storage_id, $vmid, $dst_format, undef, $src_size / 1024);
-
- my $zeroinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $dst_volid);
-
- my $create_drive = sub {
- my $vm_conf = PVE::QemuConfig->load_config($vmid);
- if (!$params->{skiplock}) {
- PVE::QemuConfig->check_lock($vm_conf);
- }
-
- if ($drive_name) {
- # should never happen as setting $drive_name is not exposed to public interface
- die "cowardly refusing to overwrite existing entry: $drive_name\n" if $vm_conf->{$drive_name};
-
- my $modified = {}; # record what $option we modify
- $modified->{$drive_name} = 1;
- $vm_conf->{pending}->{$drive_name} = $dst_volid;
- PVE::QemuConfig->write_config($vmid, $vm_conf);
-
- my $running = PVE::QemuServer::check_running($vmid);
- if ($running) {
- my $errors = {};
- PVE::QemuServer::vmconfig_hotplug_pending($vmid, $vm_conf, $storecfg, $modified, $errors);
- warn "hotplugging imported disk '$_' failed: $errors->{$_}\n" for keys %$errors;
- } else {
- PVE::QemuServer::vmconfig_apply_pending($vmid, $vm_conf, $storecfg);
- }
- } else {
- $drive_name = PVE::QemuConfig->add_unused_volume($vm_conf, $dst_volid);
- PVE::QemuConfig->write_config($vmid, $vm_conf);
- }
- };
-
- eval {
- # trap interrupts so we have a chance to clean up
- local $SIG{INT} =
- local $SIG{TERM} =
- local $SIG{QUIT} =
- local $SIG{HUP} =
- local $SIG{PIPE} = sub { die "interrupted by signal $!\n"; };
-
- PVE::Storage::activate_volumes($storecfg, [$dst_volid]);
- PVE::QemuServer::qemu_img_convert($src_path, $dst_volid, $src_size, undef, $zeroinit);
- PVE::Storage::deactivate_volumes($storecfg, [$dst_volid]);
- PVE::QemuConfig->lock_config($vmid, $create_drive);
- };
- if (my $err = $@) {
- eval { PVE::Storage::vdisk_free($storecfg, $dst_volid) };
- warn "cleanup of $dst_volid failed: $@\n" if $@;
- die $err;
- }
-
- return ($drive_name, $dst_volid);
-}
-
-1;
diff --git a/PVE/QemuServer/Makefile b/PVE/QemuServer/Makefile
index e4ed184..7a8a38f 100644
--- a/PVE/QemuServer/Makefile
+++ b/PVE/QemuServer/Makefile
@@ -1,7 +1,6 @@
SOURCES=PCI.pm \
USB.pm \
Memory.pm \
- ImportDisk.pm \
OVF.pm \
Cloudinit.pm \
Agent.pm \
diff --git a/PVE/QemuServer/OVF.pm b/PVE/QemuServer/OVF.pm
index c76c199..36b7fff 100644
--- a/PVE/QemuServer/OVF.pm
+++ b/PVE/QemuServer/OVF.pm
@@ -87,7 +87,7 @@ sub id_to_pve {
# returns two references, $qm which holds qm.conf style key/values, and \@disks
sub parse_ovf {
- my ($ovf, $debug) = @_;
+ my ($ovf, $debug, $ignore_size) = @_;
my $dom = XML::LibXML->load_xml(location => $ovf, no_blanks => 1);
@@ -220,9 +220,11 @@ ovf:Item[rasd:InstanceID='%s']/rasd:ResourceType", $controller_id);
die "error parsing $filepath, file seems not to exist at $backing_file_path\n";
}
- my $virtual_size;
- if ( !($virtual_size = PVE::Storage::file_size_info($backing_file_path)) ) {
- die "error parsing $backing_file_path, size seems to be $virtual_size\n";
+ my $virtual_size = 0;
+ if (!$ignore_size) { # Not possible if manifest is uploaded in web gui
+ if ( !($virtual_size = PVE::Storage::file_size_info($backing_file_path)) ) {
+ die "error parsing $backing_file_path: Could not get file size info: $@\n";
+ }
}
$pve_disk = {
--
2.20.1
More information about the pve-devel
mailing list