]>
git.proxmox.com Git - qemu-server.git/blob - PVE/QemuServer/ImportDisk.pm
1 package PVE
::QemuServer
::ImportDisk
;
8 use PVE
::Tools
qw(run_command extract_param);
10 # imports an external disk image to an existing VM
11 # and creates by default a drive entry unused[n] pointing to the created volume
12 # $optional->{drive_name} may be used to specify ide0, scsi1, etc ...
13 # $optional->{format} may be used to specify qcow2, raw, etc ...
15 my ($src_path, $vmid, $storage_id, $optional) = @_;
17 my $drive_name = extract_param
($optional, 'drive_name');
18 my $format = extract_param
($optional, 'format');
19 my $debug = extract_param
($optional, 'debug');
20 if ($drive_name && !(PVE
::QemuServer
::is_valid_drivename
($drive_name))) {
21 die "invalid drive name: $drive_name\n";
24 # get the needed size from source disk
25 my $src_size = PVE
::Storage
::file_size_info
($src_path);
27 # get target format, target image's path, and whether it's possible to sparseinit
28 my $storecfg = PVE
::Storage
::config
();
29 my $dst_format = PVE
::QemuServer
::resolve_dst_disk_format
($storecfg,
30 $storage_id, undef, $format);
31 warn "format : $dst_format\n" if $debug;
33 my $dst_volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storage_id, $vmid,
34 $dst_format, undef, $src_size / 1024);
35 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
37 warn "args: $src_path, $vmid, $storage_id, $optional\n",
38 "\$dst_volid: $dst_volid\n", if $debug;
40 # qemu-img convert does the hard job
41 # we don't attempt to guess filetypes ourselves
42 my $convert_command = ['qemu-img', 'convert', $src_path, '-p', '-n', '-O', $dst_format];
43 if (PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $dst_volid)) {
44 push @$convert_command, "zeroinit:$dst_path";
46 push @$convert_command, $dst_path;
49 my $create_drive = sub {
50 my $vm_conf = PVE
::QemuConfig-
>load_config($vmid);
51 PVE
::QemuConfig-
>check_lock($vm_conf);
54 # should never happen as setting $drive_name is not exposed to public interface
55 die "cowardly refusing to overwrite existing entry: $drive_name\n" if $vm_conf->{$drive_name};
57 my $modified = {}; # record what $option we modify
58 $modified->{$drive_name} = 1;
59 $vm_conf->{pending
}->{$drive_name} = $dst_volid;
60 PVE
::QemuConfig-
>write_config($vmid, $vm_conf);
62 my $running = PVE
::QemuServer
::check_running
($vmid);
65 PVE
::QemuServer
::vmconfig_hotplug_pending
($vmid, $vm_conf, $storecfg, $modified, $errors);
66 if (scalar(keys %$errors)) {
67 foreach my $k (keys %$errors) {
68 warn "$k: $errors->{$k}\n" if $debug;
69 warn "hotplugging imported disk failed\n";
73 PVE
::QemuServer
::vmconfig_apply_pending
($vmid, $vm_conf, $storecfg);
77 PVE
::QemuConfig-
>add_unused_volume($vm_conf, $dst_volid);
78 PVE
::QemuConfig-
>write_config($vmid, $vm_conf);
84 # trap interrupts so we have a chance to clean up
89 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
90 PVE
::Storage
::activate_volumes
($storecfg, [$dst_volid]);
91 run_command
($convert_command);
92 PVE
::Storage
::deactivate_volumes
($storecfg, [$dst_volid]);
93 PVE
::QemuConfig-
>lock_config($vmid, $create_drive);
98 eval { # do not die before we returned $err
99 PVE
::Storage
::vdisk_free
($storecfg, $dst_volid);