]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer/ImportDisk.pm
bump version to 8.2.1
[qemu-server.git] / PVE / QemuServer / ImportDisk.pm
CommitLineData
b94e047a
EK
1package PVE::QemuServer::ImportDisk;
2
3use strict;
4use warnings;
5
6use PVE::Storage;
7use PVE::QemuServer;
8use PVE::Tools qw(run_command extract_param);
9
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
5600c5b2
TL
12# $params->{drive_name} may be used to specify ide0, scsi1, etc ...
13# $params->{format} may be used to specify qcow2, raw, etc ...
e6ac9fed
DJ
14# $params->{skiplock} may be used to skip checking for a lock in the VM config
15# $params->{'skip-config-update'} may be used to import the disk without updating the VM config
b94e047a 16sub do_import {
5600c5b2 17 my ($src_path, $vmid, $storage_id, $params) = @_;
b94e047a 18
5600c5b2
TL
19 my $drive_name = extract_param($params, 'drive_name');
20 my $format = extract_param($params, 'format');
b94e047a
EK
21 if ($drive_name && !(PVE::QemuServer::is_valid_drivename($drive_name))) {
22 die "invalid drive name: $drive_name\n";
23 }
24
25 # get the needed size from source disk
26 my $src_size = PVE::Storage::file_size_info($src_path);
27
28 # get target format, target image's path, and whether it's possible to sparseinit
29 my $storecfg = PVE::Storage::config();
5600c5b2 30 my $dst_format = PVE::QemuServer::resolve_dst_disk_format($storecfg, $storage_id, undef, $format);
f6039ced
FE
31 warn "format '$format' is not supported by the target storage - using '$dst_format' instead\n"
32 if $format && $format ne $dst_format;
b94e047a 33
5600c5b2 34 my $dst_volid = PVE::Storage::vdisk_alloc($storecfg, $storage_id, $vmid, $dst_format, undef, $src_size / 1024);
b94e047a 35
af1f1ec0 36 my $zeroinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $dst_volid);
b94e047a
EK
37
38 my $create_drive = sub {
39 my $vm_conf = PVE::QemuConfig->load_config($vmid);
5600c5b2 40 if (!$params->{skiplock}) {
7f384190
DJ
41 PVE::QemuConfig->check_lock($vm_conf);
42 }
b94e047a
EK
43
44 if ($drive_name) {
5600c5b2
TL
45 # should never happen as setting $drive_name is not exposed to public interface
46 die "cowardly refusing to overwrite existing entry: $drive_name\n" if $vm_conf->{$drive_name};
b94e047a 47
5600c5b2
TL
48 my $modified = {}; # record what $option we modify
49 $modified->{$drive_name} = 1;
50 $vm_conf->{pending}->{$drive_name} = $dst_volid;
51 PVE::QemuConfig->write_config($vmid, $vm_conf);
b94e047a 52
5600c5b2
TL
53 my $running = PVE::QemuServer::check_running($vmid);
54 if ($running) {
55 my $errors = {};
56 PVE::QemuServer::vmconfig_hotplug_pending($vmid, $vm_conf, $storecfg, $modified, $errors);
57 warn "hotplugging imported disk '$_' failed: $errors->{$_}\n" for keys %$errors;
58 } else {
59 PVE::QemuServer::vmconfig_apply_pending($vmid, $vm_conf, $storecfg);
60 }
b94e047a 61 } else {
c75bf161 62 $drive_name = PVE::QemuConfig->add_unused_volume($vm_conf, $dst_volid);
b94e047a
EK
63 PVE::QemuConfig->write_config($vmid, $vm_conf);
64 }
b94e047a
EK
65 };
66
67 eval {
68 # trap interrupts so we have a chance to clean up
6cb0144a
EK
69 local $SIG{INT} =
70 local $SIG{TERM} =
71 local $SIG{QUIT} =
72 local $SIG{HUP} =
5600c5b2
TL
73 local $SIG{PIPE} = sub { die "interrupted by signal $!\n"; };
74
b94e047a 75 PVE::Storage::activate_volumes($storecfg, [$dst_volid]);
af1f1ec0 76 PVE::QemuServer::qemu_img_convert($src_path, $dst_volid, $src_size, undef, $zeroinit);
b94e047a 77 PVE::Storage::deactivate_volumes($storecfg, [$dst_volid]);
e6ac9fed 78 PVE::QemuConfig->lock_config($vmid, $create_drive) if !$params->{'skip-config-update'};
b94e047a 79 };
5600c5b2
TL
80 if (my $err = $@) {
81 eval { PVE::Storage::vdisk_free($storecfg, $dst_volid) };
82 warn "cleanup of $dst_volid failed: $@\n" if $@;
b94e047a
EK
83 die $err;
84 }
c75bf161
TL
85
86 return ($drive_name, $dst_volid);
b94e047a
EK
87}
88
891;