]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer/ImportDisk.pm
fix reverting for non-existing configs
[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
12# $optional->{drive_name} may be used to specify ide0, scsi1, etc ...
13# $optional->{format} may be used to specify qcow2, raw, etc ...
14sub do_import {
15 my ($src_path, $vmid, $storage_id, $optional) = @_;
16
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";
22 }
23
24 # get the needed size from source disk
25 my $src_size = PVE::Storage::file_size_info($src_path);
26
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;
32
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);
36
37 warn "args: $src_path, $vmid, $storage_id, $optional\n",
38 "\$dst_volid: $dst_volid\n", if $debug;
39
af1f1ec0 40 my $zeroinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $dst_volid);
b94e047a
EK
41
42 my $create_drive = sub {
43 my $vm_conf = PVE::QemuConfig->load_config($vmid);
44 PVE::QemuConfig->check_lock($vm_conf);
45
46 if ($drive_name) {
47 # should never happen as setting $drive_name is not exposed to public interface
21463b9a 48 die "cowardly refusing to overwrite existing entry: $drive_name\n" if $vm_conf->{$drive_name};
b94e047a
EK
49
50 my $modified = {}; # record what $option we modify
51 $modified->{$drive_name} = 1;
52 $vm_conf->{pending}->{$drive_name} = $dst_volid;
53 PVE::QemuConfig->write_config($vmid, $vm_conf);
54
55 my $running = PVE::QemuServer::check_running($vmid);
56 if ($running) {
57 my $errors = {};
58 PVE::QemuServer::vmconfig_hotplug_pending($vmid, $vm_conf, $storecfg, $modified, $errors);
0f0aa6b7
FG
59 if (scalar(keys %$errors)) {
60 foreach my $k (keys %$errors) {
61 warn "$k: $errors->{$k}\n" if $debug;
62 warn "hotplugging imported disk failed\n";
63 }
64 }
b94e047a
EK
65 } else {
66 PVE::QemuServer::vmconfig_apply_pending($vmid, $vm_conf, $storecfg);
67 }
68
69 } else {
70 PVE::QemuConfig->add_unused_volume($vm_conf, $dst_volid);
71 PVE::QemuConfig->write_config($vmid, $vm_conf);
72 }
73
74 };
75
76 eval {
77 # trap interrupts so we have a chance to clean up
6cb0144a
EK
78 local $SIG{INT} =
79 local $SIG{TERM} =
80 local $SIG{QUIT} =
81 local $SIG{HUP} =
82 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
b94e047a 83 PVE::Storage::activate_volumes($storecfg, [$dst_volid]);
af1f1ec0 84 PVE::QemuServer::qemu_img_convert($src_path, $dst_volid, $src_size, undef, $zeroinit);
b94e047a
EK
85 PVE::Storage::deactivate_volumes($storecfg, [$dst_volid]);
86 PVE::QemuConfig->lock_config($vmid, $create_drive);
87 };
88
89 my $err = $@;
90 if ($err) {
91 eval { # do not die before we returned $err
92 PVE::Storage::vdisk_free($storecfg, $dst_volid);
93 };
94 die $err;
95 }
96}
97
981;