[pve-devel] [PATCH qemu-server v4 2/3] Add ImportDisk module to import external disk images into a VM

Emmanuel Kasper e.kasper at proxmox.com
Tue May 9 16:26:05 CEST 2017


Each disk passed as paramater is add as 'unused[n]' in the vm.conf
(the default) or ide[n]|scsi[n]|sata[n]
We rely on qemu-img(1) convert heuristics to detect the file type,
as this works in most case.
---
 PVE/QemuServer/ImportDisk.pm | 96 ++++++++++++++++++++++++++++++++++++++++++++
 PVE/QemuServer/Makefile      |  1 +
 2 files changed, 97 insertions(+)
 create mode 100755 PVE/QemuServer/ImportDisk.pm

diff --git a/PVE/QemuServer/ImportDisk.pm b/PVE/QemuServer/ImportDisk.pm
new file mode 100755
index 0000000..6d1ddbb
--- /dev/null
+++ b/PVE/QemuServer/ImportDisk.pm
@@ -0,0 +1,96 @@
+package PVE::QemuServer::ImportDisk;
+
+use strict;
+use warnings;
+use Data::Dumper;
+
+use PVE::Storage;
+use PVE::Storage::Plugin;
+use PVE::QemuServer;
+use PVE::Tools 'run_command';
+
+# import an external disk image to an existing VM
+# and create a drive entry unused[n] pointing to the created volume
+# $optional->{drive_name} may be used to specify ide0, scsi1, etc ...
+# $optional->{format} may be used to specify qcow2, raw, etc ...
+sub do_import {
+    my ($src_path, $vmid, $storage_id, $optional) = @_;
+    my $dst = {};
+
+    # get the needed size from  source disk
+    my ($virtual_src_size, $src_format, $used, $parent) = PVE::Storage::Plugin::file_size_info($src_path);
+
+    # get target format, target image's path, and whether it's possible to sparseinit
+    my $storecfg = PVE::Storage::config();
+    if ($optional && $optional->{format}) {
+	$dst->{format} = PVE::QemuServer::choose_dst_disk_format($storecfg, $storage_id, undef, $optional->{format});
+	warn Dumper("format :", $dst->{format}) if $optional && $optional->{debug};
+    }
+    $dst->{volid} = PVE::Storage::vdisk_alloc($storecfg,
+	$storage_id, $vmid, $dst->{format}, undef, $virtual_src_size / 1024);
+    $dst->{path} = PVE::Storage::path($storecfg, $dst->{volid});
+    $dst->{has_sparseinit} = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $dst->{volid});
+    $dst->{size} = $virtual_src_size;
+
+    warn "args: ", Dumper($src_path, $vmid, $storage_id, $optional),
+	"\$dst->{volid}: $dst->{volid}\n",
+	"\$dst: ", Dumper($dst) if $optional && $optional->{debug};
+
+    # qemu-img convert does the hard job
+    # we don't attempt to guest filetypes ourselves
+    my $convert_command = ['qemu-img', 'convert', $src_path, '-p', '-n'];
+    if ($dst->{format}) {
+	push @$convert_command, '-O', $dst->{format};
+    }
+    if ($dst->{has_sparseinit}) {
+	push @$convert_command, "zeroinit:$dst->{path}";
+    } else {
+	push @$convert_command, $dst->{path};
+    }
+
+    my $config_key;
+    eval {
+	# trap interrupts so we have a chance to clean up
+	local $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub {
+	    die "interrupted by signal\n";
+	};
+	PVE::Storage::activate_volumes($storecfg, [$dst->{volid}]);
+	run_command($convert_command);
+	PVE::Storage::deactivate_volumes($storecfg, [$dst->{volid}]);
+	$config_key = __create_disk_entry($storecfg, $vmid, $optional->{drive_name}, $dst);
+    };
+    my $err = $@;
+    if ($err) {
+	PVE::Storage::vdisk_free($storecfg, $dst->{volid}) if PVE::Storage::path($storecfg, $dst->{volid});
+	die $err;
+    }
+
+    return $config_key;
+}
+
+sub __create_disk_entry {
+    my ($storecfg, $vmid, $drive_name, $dst) = @_;
+    if (PVE::QemuServer::vm_is_volid_owner($storecfg, $vmid, $dst->{volid})) {
+	my $vm_conf = PVE::QemuConfig->load_config($vmid);
+
+	my $create_active_drive = sub {
+	    if (PVE::QemuServer::is_valid_drivename($drive_name)) {
+		$vm_conf->{$drive_name} = PVE::QemuServer::print_drive($vmid, { file => $dst->{volid}, size => $dst->{size} });
+		PVE::QemuConfig->write_config($vmid, $vm_conf);
+		return $drive_name;
+	    }
+	    return undef;
+	};
+
+	my $create_unused_drive =  sub {
+	    my $disk_key = PVE::QemuConfig->add_unused_volume($vm_conf, $dst->{volid});
+	    PVE::QemuConfig->write_config($vmid, $vm_conf);
+	    return $disk_key;
+	};
+
+	my $create_entry = $drive_name ? $create_active_drive : $create_unused_drive;
+	return PVE::QemuConfig->lock_config($vmid, $create_entry);
+    }
+}
+
+1;
diff --git a/PVE/QemuServer/Makefile b/PVE/QemuServer/Makefile
index 06617c5..f75f2e6 100644
--- a/PVE/QemuServer/Makefile
+++ b/PVE/QemuServer/Makefile
@@ -3,3 +3,4 @@ install:
 	install -D -m 0644 PCI.pm ${DESTDIR}${PERLDIR}/PVE/QemuServer/PCI.pm
 	install -D -m 0644 USB.pm ${DESTDIR}${PERLDIR}/PVE/QemuServer/USB.pm
 	install -D -m 0644 Memory.pm ${DESTDIR}${PERLDIR}/PVE/QemuServer/Memory.pm
+	install -D -m 0644 ImportDisk.pm ${DESTDIR}${PERLDIR}/PVE/QemuServer/ImportDisk.pm
-- 
2.11.0





More information about the pve-devel mailing list