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

Emmanuel Kasper e.kasper at proxmox.com
Tue Apr 25 10:56:01 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/DiskImport.pm | 93 ++++++++++++++++++++++++++++++++++++++++++++
 PVE/QemuServer/Makefile      |  1 +
 2 files changed, 94 insertions(+)
 create mode 100755 PVE/QemuServer/DiskImport.pm

diff --git a/PVE/QemuServer/DiskImport.pm b/PVE/QemuServer/DiskImport.pm
new file mode 100755
index 0000000..2d210ae
--- /dev/null
+++ b/PVE/QemuServer/DiskImport.pm
@@ -0,0 +1,93 @@
+package PVE::QemuServer::DiskImport;
+
+use strict;
+use warnings;
+use Data::Dumper;
+
+use PVE::Storage;
+use PVE::Storage::Plugin;
+use PVE::QemuServer;
+use PVE::Tools 'run_command';
+
+# given a hash reference with the following structure,
+# { src_path => $path_to_file,
+#   vmid => target_vmid,
+#   storage_id => $storage_id,
+#   disk_entry => $disk_entry, # leave this undef to create an 'unused' volume
+#   debug => 0 }
+# this sub will import an external disk image to a PVE storage
+# and create a disk_entry key (ide0 | unused0) pointing to the created volume
+sub do_import {
+    my ($args) = @_;
+    my $dst = {}; # parameters that we will pass to qemu-img
+
+    # get the needed size from  source disk
+    my ($virtual_src_size, $src_format, $used, $parent) = PVE::Storage::Plugin::file_size_info($args->{src_path});
+
+    # allocate an image of the needed size
+    my $storecfg = PVE::Storage::config();
+    $dst->{volid} = PVE::Storage::vdisk_alloc($storecfg,
+					    $args->{storage_id}, $args->{vmid}, undef, undef, $virtual_src_size / 1024);
+
+    # get target image's path, whether it's possible to sparseinit, and target format
+    $dst->{path} = PVE::Storage::path($storecfg, $dst->{volid});
+    $dst->{sparseinit} = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $dst->{volid});
+    $dst->{format} = PVE::QemuServer::qemu_img_format($storecfg, $args->{storage_id});
+    $dst->{size} = $virtual_src_size;
+
+    warn "\$args: ", Dumper($args), "\$dst->{volid}: $dst->{volid}", "\$dst: ", Dumper($dst) if $args->{debug};
+
+    # qemu-img convert does the hard job
+    # we don't attempt to guest filetypes ourselves
+    my $convert_command = ['qemu-img', 'convert', $args->{src_path}, '-p', '-n'];
+    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, $args->{vmid}, $args->{disk_entry}, $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, $disk_entry, $dst) = @_;
+    if (PVE::QemuServer::vm_is_volid_owner($storecfg, $vmid, $dst->{volid})) {
+	my $vm_conf = PVE::QemuConfig->load_config($vmid);
+
+	my $create_active_disk_entry = sub {
+	    if (PVE::QemuServer::is_valid_disk_entryname($disk_entry)) {
+		my $vm_conf->{$disk_entry} = PVE::QemuServer::print_disk_entry($vmid, { file => $dst->{volid}, size => $dst->{size} });
+		PVE::QemuConfig->write_config($vmid, $vm_conf);
+		return $disk_entry;
+	    }
+	    return undef;
+	};
+
+	my $create_unused_disk_entry =  sub {
+	    my $disk_key = PVE::QemuConfig->add_unused_volume($vm_conf, $dst->{volid});
+	    PVE::QemuConfig->write_config($vmid, $vm_conf);
+	    return $disk_key;
+	};
+
+	return PVE::QemuConfig->lock_config($vmid, $disk_entry ? $create_active_disk_entry : $create_unused_disk_entry);
+    }
+}
+
+1;
diff --git a/PVE/QemuServer/Makefile b/PVE/QemuServer/Makefile
index 06617c5..b61a99a 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 DiskImport.pm ${DESTDIR}${PERLDIR}/PVE/QemuServer/DiskImport.pm
-- 
2.11.0





More information about the pve-devel mailing list