]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
map_storage: check for definedness not perl-truthiness
[qemu-server.git] / PVE / QemuServer.pm
CommitLineData
1e3baf05
DM
1package PVE::QemuServer;
2
3use strict;
990fc5e2 4use warnings;
3ff84d6f 5
5da072fb
TL
6use Cwd 'abs_path';
7use Digest::SHA;
8use Fcntl ':flock';
9use Fcntl;
1e3baf05 10use File::Basename;
5da072fb 11use File::Copy qw(copy);
1e3baf05
DM
12use File::Path;
13use File::stat;
14use Getopt::Long;
5da072fb
TL
15use IO::Dir;
16use IO::File;
17use IO::Handle;
18use IO::Select;
19use IO::Socket::UNIX;
1e3baf05 20use IPC::Open3;
c971c4f2 21use JSON;
1f30ac3a 22use MIME::Base64;
5da072fb
TL
23use POSIX;
24use Storable qw(dclone);
25use Time::HiRes qw(gettimeofday);
26use URI::Escape;
425441e6 27use UUID;
5da072fb 28
1e3baf05 29use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
48cf040f 30use PVE::DataCenterConfig;
5da072fb 31use PVE::Exception qw(raise raise_param_exc);
81d6e4e1 32use PVE::GuestHelpers qw(safe_string_ne safe_num_ne safe_boolean_ne);
1e3baf05 33use PVE::INotify;
5da072fb 34use PVE::JSONSchema qw(get_standard_option);
1e3baf05 35use PVE::ProcFSTools;
91bd6c90 36use PVE::RPCEnvironment;
5da072fb 37use PVE::Storage;
b71351a7 38use PVE::SysFSTools;
d04d6af1 39use PVE::Systemd;
05a4c550 40use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline file_get_contents dir_glob_foreach get_host_arch $IPV6RE);
5da072fb
TL
41
42use PVE::QMPClient;
43use PVE::QemuConfig;
2f18c84d 44use PVE::QemuServer::Helpers qw(min_version config_aware_timeout);
5da072fb 45use PVE::QemuServer::Cloudinit;
d786a274 46use PVE::QemuServer::CPUConfig qw(print_cpu_device get_cpu_options);
e0fd2b2f 47use PVE::QemuServer::Drive qw(is_valid_drivename drive_is_cloudinit drive_is_cdrom parse_drive print_drive foreach_drive foreach_volid);
2ea5fb7e 48use PVE::QemuServer::Machine;
5da072fb 49use PVE::QemuServer::Memory;
0a13e08e 50use PVE::QemuServer::Monitor qw(mon_cmd);
5da072fb
TL
51use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port);
52use PVE::QemuServer::USB qw(parse_usb_device);
1e3baf05 53
28e129cc
AD
54my $have_sdn;
55eval {
56 require PVE::Network::SDN::Zones;
57 $have_sdn = 1;
58};
59
102cf9d8 60my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
96ed3574
WB
61my $OVMF = {
62 x86_64 => [
63 "$EDK2_FW_BASE/OVMF_CODE.fd",
64 "$EDK2_FW_BASE/OVMF_VARS.fd"
65 ],
66 aarch64 => [
67 "$EDK2_FW_BASE/AAVMF_CODE.fd",
68 "$EDK2_FW_BASE/AAVMF_VARS.fd"
69 ],
70};
2ddc0a5c 71
7f0b5beb 72my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
1e3baf05 73
19672434 74# Note about locking: we use flock on the config file protect
1e3baf05
DM
75# against concurent actions.
76# Aditionaly, we have a 'lock' setting in the config file. This
22c377f0 77# can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
1e3baf05
DM
78# allowed when such lock is set. But you can ignore this kind of
79# lock with the --skiplock flag.
80
97d62eb7 81cfs_register_file('/qemu-server/',
1858638f
DM
82 \&parse_vm_config,
83 \&write_vm_config);
1e3baf05 84
3ea94c60
DM
85PVE::JSONSchema::register_standard_option('pve-qm-stateuri', {
86 description => "Some command save/restore state from this location.",
87 type => 'string',
88 maxLength => 128,
89 optional => 1,
90});
91
c6737ef1
DC
92PVE::JSONSchema::register_standard_option('pve-qemu-machine', {
93 description => "Specifies the Qemu machine type.",
94 type => 'string',
9471e48b 95 pattern => '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
c6737ef1
DC
96 maxLength => 40,
97 optional => 1,
98});
99
bf8fc5a3
FG
100
101sub map_storage {
102 my ($map, $source) = @_;
103
104 return $source if !defined($map);
105
106 return $map->{entries}->{$source}
b6d9b54b 107 if $map->{entries} && defined($map->{entries}->{$source});
bf8fc5a3
FG
108
109 return $map->{default} if $map->{default};
110
111 # identity (fallback)
112 return $source;
113}
114
115PVE::JSONSchema::register_standard_option('pve-targetstorage', {
116 description => "Mapping from source to target storages. Providing only a single storage ID maps all source storages to that storage. Providing the special value '1' will map each source storage to itself.",
117 type => 'string',
118 format => 'storagepair-list',
119 optional => 1,
120});
121
1e3baf05
DM
122#no warnings 'redefine';
123
c8effec3
AD
124sub cgroups_write {
125 my ($controller, $vmid, $option, $value) = @_;
126
3a515a88
DM
127 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
128 PVE::ProcFSTools::write_proc_entry($path, $value);
c8effec3
AD
129
130}
131
38277afc
TL
132my $nodename_cache;
133sub nodename {
134 $nodename_cache //= PVE::INotify::nodename();
135 return $nodename_cache;
136}
1e3baf05 137
ec3582b5
WB
138my $watchdog_fmt = {
139 model => {
140 default_key => 1,
141 type => 'string',
142 enum => [qw(i6300esb ib700)],
143 description => "Watchdog type to emulate.",
144 default => 'i6300esb',
145 optional => 1,
146 },
147 action => {
148 type => 'string',
149 enum => [qw(reset shutdown poweroff pause debug none)],
150 description => "The action to perform if after activation the guest fails to poll the watchdog in time.",
151 optional => 1,
152 },
153};
154PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
155
9d66b397
SI
156my $agent_fmt = {
157 enabled => {
158 description => "Enable/disable Qemu GuestAgent.",
159 type => 'boolean',
160 default => 0,
161 default_key => 1,
162 },
163 fstrim_cloned_disks => {
164 description => "Run fstrim after cloning/moving a disk.",
165 type => 'boolean',
166 optional => 1,
167 default => 0
168 },
48657158
MD
169 type => {
170 description => "Select the agent type",
171 type => 'string',
172 default => 'virtio',
173 optional => 1,
174 enum => [qw(virtio isa)],
175 },
9d66b397
SI
176};
177
55655ebc
DC
178my $vga_fmt = {
179 type => {
180 description => "Select the VGA type.",
181 type => 'string',
182 default => 'std',
183 optional => 1,
184 default_key => 1,
7c954c42 185 enum => [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
55655ebc
DC
186 },
187 memory => {
188 description => "Sets the VGA memory (in MiB). Has no effect with serial display.",
189 type => 'integer',
190 optional => 1,
191 minimum => 4,
192 maximum => 512,
193 },
194};
195
6dbcb073
DC
196my $ivshmem_fmt = {
197 size => {
198 type => 'integer',
199 minimum => 1,
200 description => "The size of the file in MB.",
201 },
202 name => {
203 type => 'string',
204 pattern => '[a-zA-Z0-9\-]+',
205 optional => 1,
206 format_description => 'string',
207 description => "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
208 },
209};
210
1448547f
AL
211my $audio_fmt = {
212 device => {
213 type => 'string',
214 enum => [qw(ich9-intel-hda intel-hda AC97)],
215 description => "Configure an audio device."
216 },
217 driver => {
218 type => 'string',
219 enum => ['spice'],
220 default => 'spice',
221 optional => 1,
222 description => "Driver backend for the audio device."
223 },
224};
225
c4df18db
AL
226my $spice_enhancements_fmt = {
227 foldersharing => {
228 type => 'boolean',
229 optional => 1,
d282a24d 230 default => '0',
c4df18db
AL
231 description => "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
232 },
233 videostreaming => {
234 type => 'string',
235 enum => ['off', 'all', 'filter'],
d282a24d 236 default => 'off',
c4df18db
AL
237 optional => 1,
238 description => "Enable video streaming. Uses compression for detected video streams."
239 },
240};
241
2cf61f33
SR
242my $rng_fmt = {
243 source => {
244 type => 'string',
245 enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
246 default_key => 1,
247 description => "The file on the host to gather entropy from. In most"
248 . " cases /dev/urandom should be preferred over /dev/random"
249 . " to avoid entropy-starvation issues on the host. Using"
250 . " urandom does *not* decrease security in any meaningful"
251 . " way, as it's still seeded from real entropy, and the"
252 . " bytes provided will most likely be mixed with real"
253 . " entropy on the guest as well. /dev/hwrng can be used"
254 . " to pass through a hardware RNG from the host.",
255 },
256 max_bytes => {
257 type => 'integer',
258 description => "Maximum bytes of entropy injected into the guest every"
259 . " 'period' milliseconds. Prefer a lower value when using"
260 . " /dev/random as source. Use 0 to disable limiting"
261 . " (potentially dangerous!).",
262 optional => 1,
263
264 # default is 1 KiB/s, provides enough entropy to the guest to avoid
265 # boot-starvation issues (e.g. systemd etc...) while allowing no chance
266 # of overwhelming the host, provided we're reading from /dev/urandom
267 default => 1024,
268 },
269 period => {
270 type => 'integer',
271 description => "Every 'period' milliseconds the entropy-injection quota"
272 . " is reset, allowing the guest to retrieve another"
273 . " 'max_bytes' of entropy.",
274 optional => 1,
275 default => 1000,
276 },
277};
278
1e3baf05
DM
279my $confdesc = {
280 onboot => {
281 optional => 1,
282 type => 'boolean',
283 description => "Specifies whether a VM will be started during system bootup.",
284 default => 0,
285 },
286 autostart => {
287 optional => 1,
288 type => 'boolean',
289 description => "Automatic restart after crash (currently ignored).",
290 default => 0,
291 },
2ff09f52
DA
292 hotplug => {
293 optional => 1,
b3c2bdd1
DM
294 type => 'string', format => 'pve-hotplug-features',
295 description => "Selectively enable hotplug features. This is a comma separated list of hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable hotplug completely. Value '1' is an alias for the default 'network,disk,usb'.",
296 default => 'network,disk,usb',
2ff09f52 297 },
1e3baf05
DM
298 reboot => {
299 optional => 1,
300 type => 'boolean',
301 description => "Allow reboot. If set to '0' the VM exit on reboot.",
302 default => 1,
303 },
304 lock => {
305 optional => 1,
306 type => 'string',
307 description => "Lock/unlock the VM.",
159719e5 308 enum => [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
1e3baf05
DM
309 },
310 cpulimit => {
311 optional => 1,
c6f773b8 312 type => 'number',
52261945
DM
313 description => "Limit of CPU usage.",
314 verbose_description => "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has total of '2' CPU time. Value '0' indicates no CPU limit.",
1e3baf05 315 minimum => 0,
c6f773b8 316 maximum => 128,
52261945 317 default => 0,
1e3baf05
DM
318 },
319 cpuunits => {
320 optional => 1,
321 type => 'integer',
52261945 322 description => "CPU weight for a VM.",
237239bf
PA
323 verbose_description => "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to weights of all the other running VMs.",
324 minimum => 2,
325 maximum => 262144,
613d76a1 326 default => 1024,
1e3baf05
DM
327 },
328 memory => {
329 optional => 1,
330 type => 'integer',
7878afeb 331 description => "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
1e3baf05
DM
332 minimum => 16,
333 default => 512,
334 },
13a48620
DA
335 balloon => {
336 optional => 1,
337 type => 'integer',
8b1accf7
DM
338 description => "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
339 minimum => 0,
340 },
341 shares => {
342 optional => 1,
343 type => 'integer',
82329cd5 344 description => "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
8b1accf7
DM
345 minimum => 0,
346 maximum => 50000,
347 default => 1000,
13a48620 348 },
1e3baf05
DM
349 keyboard => {
350 optional => 1,
351 type => 'string',
f889aa0f 352 description => "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
aea47dd6 353 "It should not be necessary to set it.",
e95fe75f 354 enum => PVE::Tools::kvmkeymaplist(),
aea47dd6 355 default => undef,
1e3baf05
DM
356 },
357 name => {
358 optional => 1,
7fabe17d 359 type => 'string', format => 'dns-name',
1e3baf05
DM
360 description => "Set a name for the VM. Only used on the configuration web interface.",
361 },
cdd20088
AD
362 scsihw => {
363 optional => 1,
364 type => 'string',
52261945 365 description => "SCSI controller model",
6731a4cf 366 enum => [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
cdd20088
AD
367 default => 'lsi',
368 },
1e3baf05
DM
369 description => {
370 optional => 1,
371 type => 'string',
0581fe4f 372 description => "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
1e3baf05
DM
373 },
374 ostype => {
375 optional => 1,
376 type => 'string',
0cb9971e 377 enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
52261945
DM
378 description => "Specify guest operating system.",
379 verbose_description => <<EODESC,
380Specify guest operating system. This is used to enable special
381optimization/features for specific operating systems:
382
383[horizontal]
384other;; unspecified OS
385wxp;; Microsoft Windows XP
386w2k;; Microsoft Windows 2000
387w2k3;; Microsoft Windows 2003
388w2k8;; Microsoft Windows 2008
389wvista;; Microsoft Windows Vista
390win7;; Microsoft Windows 7
44c2a647
TL
391win8;; Microsoft Windows 8/2012/2012r2
392win10;; Microsoft Windows 10/2016
52261945 393l24;; Linux 2.4 Kernel
a5269260 394l26;; Linux 2.6 - 5.X Kernel
52261945 395solaris;; Solaris/OpenSolaris/OpenIndiania kernel
1e3baf05
DM
396EODESC
397 },
398 boot => {
399 optional => 1,
400 type => 'string',
401 description => "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
402 pattern => '[acdn]{1,4}',
32baffb4 403 default => 'cdn',
1e3baf05
DM
404 },
405 bootdisk => {
406 optional => 1,
407 type => 'string', format => 'pve-qm-bootdisk',
408 description => "Enable booting from specified disk.",
03e480fc 409 pattern => '(ide|sata|scsi|virtio)\d+',
1e3baf05
DM
410 },
411 smp => {
412 optional => 1,
413 type => 'integer',
414 description => "The number of CPUs. Please use option -sockets instead.",
415 minimum => 1,
416 default => 1,
417 },
418 sockets => {
419 optional => 1,
420 type => 'integer',
421 description => "The number of CPU sockets.",
422 minimum => 1,
423 default => 1,
424 },
425 cores => {
426 optional => 1,
427 type => 'integer',
428 description => "The number of cores per socket.",
429 minimum => 1,
430 default => 1,
431 },
8a010eae
AD
432 numa => {
433 optional => 1,
434 type => 'boolean',
1917695c 435 description => "Enable/disable NUMA.",
8a010eae
AD
436 default => 0,
437 },
7023f3ea
AD
438 hugepages => {
439 optional => 1,
440 type => 'string',
441 description => "Enable/disable hugepages memory.",
442 enum => [qw(any 2 1024)],
443 },
de9d1e55 444 vcpus => {
3bd18e48
AD
445 optional => 1,
446 type => 'integer',
de9d1e55 447 description => "Number of hotplugged vcpus.",
3bd18e48 448 minimum => 1,
de9d1e55 449 default => 0,
3bd18e48 450 },
1e3baf05
DM
451 acpi => {
452 optional => 1,
453 type => 'boolean',
454 description => "Enable/disable ACPI.",
455 default => 1,
456 },
bc84dcca 457 agent => {
ab6a046f 458 optional => 1,
9d66b397
SI
459 description => "Enable/disable Qemu GuestAgent and its properties.",
460 type => 'string',
461 format => $agent_fmt,
ab6a046f 462 },
1e3baf05
DM
463 kvm => {
464 optional => 1,
465 type => 'boolean',
466 description => "Enable/disable KVM hardware virtualization.",
467 default => 1,
468 },
469 tdf => {
470 optional => 1,
471 type => 'boolean',
8c559505
DM
472 description => "Enable/disable time drift fix.",
473 default => 0,
1e3baf05 474 },
19672434 475 localtime => {
1e3baf05
DM
476 optional => 1,
477 type => 'boolean',
478 description => "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
479 },
480 freeze => {
481 optional => 1,
482 type => 'boolean',
483 description => "Freeze CPU at startup (use 'c' monitor command to start execution).",
484 },
485 vga => {
486 optional => 1,
55655ebc
DC
487 type => 'string', format => $vga_fmt,
488 description => "Configure the VGA hardware.",
489 verbose_description => "Configure the VGA Hardware. If you want to use ".
490 "high resolution modes (>= 1280x1024x16) you may need to increase " .
491 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
492 "is 'std' for all OS types besides some Windows versions (XP and " .
493 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
494 "display server. For win* OS you can select how many independent " .
495 "displays you want, Linux guests can add displays them self.\n".
496 "You can also run without any graphic card, using a serial device as terminal.",
1e3baf05 497 },
0ea9541d
DM
498 watchdog => {
499 optional => 1,
500 type => 'string', format => 'pve-qm-watchdog',
52261945
DM
501 description => "Create a virtual hardware watchdog device.",
502 verbose_description => "Create a virtual hardware watchdog device. Once enabled" .
1917695c
TL
503 " (by a guest action), the watchdog must be periodically polled " .
504 "by an agent inside the guest or else the watchdog will reset " .
505 "the guest (or execute the respective action specified)",
0ea9541d 506 },
1e3baf05
DM
507 startdate => {
508 optional => 1,
19672434 509 type => 'string',
1e3baf05
DM
510 typetext => "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
511 description => "Set the initial date of the real time clock. Valid format for date are: 'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
512 pattern => '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
513 default => 'now',
514 },
43574f73 515 startup => get_standard_option('pve-startup-order'),
68eda3ab
AD
516 template => {
517 optional => 1,
518 type => 'boolean',
519 description => "Enable/disable Template.",
520 default => 0,
521 },
1e3baf05
DM
522 args => {
523 optional => 1,
524 type => 'string',
52261945
DM
525 description => "Arbitrary arguments passed to kvm.",
526 verbose_description => <<EODESCR,
c7a8aad6 527Arbitrary arguments passed to kvm, for example:
1e3baf05
DM
528
529args: -no-reboot -no-hpet
c7a8aad6
FG
530
531NOTE: this option is for experts only.
1e3baf05
DM
532EODESCR
533 },
534 tablet => {
535 optional => 1,
536 type => 'boolean',
537 default => 1,
52261945
DM
538 description => "Enable/disable the USB tablet device.",
539 verbose_description => "Enable/disable the USB tablet device. This device is " .
1917695c
TL
540 "usually needed to allow absolute mouse positioning with VNC. " .
541 "Else the mouse runs out of sync with normal VNC clients. " .
542 "If you're running lots of console-only guests on one host, " .
543 "you may consider disabling this to save some context switches. " .
544 "This is turned off by default if you use spice (-vga=qxl).",
1e3baf05
DM
545 },
546 migrate_speed => {
547 optional => 1,
548 type => 'integer',
549 description => "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
550 minimum => 0,
551 default => 0,
552 },
553 migrate_downtime => {
554 optional => 1,
04432191 555 type => 'number',
1e3baf05
DM
556 description => "Set maximum tolerated downtime (in seconds) for migrations.",
557 minimum => 0,
04432191 558 default => 0.1,
1e3baf05
DM
559 },
560 cdrom => {
561 optional => 1,
b799312f 562 type => 'string', format => 'pve-qm-ide',
8485b9ba 563 typetext => '<volume>',
1e3baf05
DM
564 description => "This is an alias for option -ide2",
565 },
566 cpu => {
567 optional => 1,
568 description => "Emulated CPU type.",
569 type => 'string',
5d008ad3 570 format => 'pve-vm-cpu-conf',
1e3baf05 571 },
b7ba6b79
DM
572 parent => get_standard_option('pve-snapshot-name', {
573 optional => 1,
574 description => "Parent snapshot name. This is used internally, and should not be modified.",
575 }),
982c7f12
DM
576 snaptime => {
577 optional => 1,
578 description => "Timestamp for snapshots.",
579 type => 'integer',
580 minimum => 0,
581 },
18bfb361
DM
582 vmstate => {
583 optional => 1,
584 type => 'string', format => 'pve-volume-id',
585 description => "Reference to a volume which stores the VM state. This is used internally for snapshots.",
586 },
253624c7
FG
587 vmstatestorage => get_standard_option('pve-storage-id', {
588 description => "Default storage for VM state volumes/files.",
589 optional => 1,
590 }),
c6737ef1
DC
591 runningmachine => get_standard_option('pve-qemu-machine', {
592 description => "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
593 }),
594 machine => get_standard_option('pve-qemu-machine'),
d731ecbe
WB
595 arch => {
596 description => "Virtual processor architecture. Defaults to the host.",
597 optional => 1,
598 type => 'string',
599 enum => [qw(x86_64 aarch64)],
600 },
2796e7d5
DM
601 smbios1 => {
602 description => "Specify SMBIOS type 1 fields.",
603 type => 'string', format => 'pve-qm-smbios1',
5d004b00 604 maxLength => 512,
2796e7d5
DM
605 optional => 1,
606 },
cb0e4540
AG
607 protection => {
608 optional => 1,
609 type => 'boolean',
52261945 610 description => "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
cb0e4540
AG
611 default => 0,
612 },
3edb45e7 613 bios => {
a783c78e 614 optional => 1,
3edb45e7
DM
615 type => 'string',
616 enum => [ qw(seabios ovmf) ],
617 description => "Select BIOS implementation.",
618 default => 'seabios',
a783c78e 619 },
6ee499ff
DC
620 vmgenid => {
621 type => 'string',
622 pattern => '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
623 format_description => 'UUID',
f7ed64e7
TL
624 description => "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
625 verbose_description => "The VM generation ID (vmgenid) device exposes a".
626 " 128-bit integer value identifier to the guest OS. This allows to".
627 " notify the guest operating system when the virtual machine is".
628 " executed with a different configuration (e.g. snapshot execution".
629 " or creation from a template). The guest operating system notices".
630 " the change, and is then able to react as appropriate by marking".
631 " its copies of distributed databases as dirty, re-initializing its".
632 " random number generator, etc.\n".
633 "Note that auto-creation only works when done throug API/CLI create".
634 " or update methods, but not when manually editing the config file.",
635 default => "1 (autogenerated)",
6ee499ff
DC
636 optional => 1,
637 },
9e784b11
DC
638 hookscript => {
639 type => 'string',
640 format => 'pve-volume-id',
641 optional => 1,
642 description => "Script that will be executed during various steps in the vms lifetime.",
643 },
6dbcb073
DC
644 ivshmem => {
645 type => 'string',
646 format => $ivshmem_fmt,
647 description => "Inter-VM shared memory. Useful for direct communication between VMs, or to the host.",
648 optional => 1,
2e7b5925
AL
649 },
650 audio0 => {
651 type => 'string',
1448547f 652 format => $audio_fmt,
194b65f1 653 description => "Configure a audio device, useful in combination with QXL/Spice.",
2e7b5925
AL
654 optional => 1
655 },
c4df18db
AL
656 spice_enhancements => {
657 type => 'string',
658 format => $spice_enhancements_fmt,
659 description => "Configure additional enhancements for SPICE.",
660 optional => 1
661 },
b8e7068a
DC
662 tags => {
663 type => 'string', format => 'pve-tag-list',
664 description => 'Tags of the VM. This is only meta information.',
665 optional => 1,
666 },
2cf61f33
SR
667 rng0 => {
668 type => 'string',
669 format => $rng_fmt,
670 description => "Configure a VirtIO-based Random Number Generator.",
671 optional => 1,
672 },
9ed7a77c
WB
673};
674
cb702ebe
DL
675my $cicustom_fmt = {
676 meta => {
677 type => 'string',
678 optional => 1,
679 description => 'Specify a custom file containing all meta data passed to the VM via cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
680 format => 'pve-volume-id',
681 format_description => 'volume',
682 },
683 network => {
684 type => 'string',
685 optional => 1,
686 description => 'Specify a custom file containing all network data passed to the VM via cloud-init.',
687 format => 'pve-volume-id',
688 format_description => 'volume',
689 },
690 user => {
691 type => 'string',
692 optional => 1,
693 description => 'Specify a custom file containing all user data passed to the VM via cloud-init.',
694 format => 'pve-volume-id',
695 format_description => 'volume',
696 },
697};
698PVE::JSONSchema::register_format('pve-qm-cicustom', $cicustom_fmt);
699
9ed7a77c 700my $confdesc_cloudinit = {
41cd94a0
WB
701 citype => {
702 optional => 1,
703 type => 'string',
498cdc36 704 description => 'Specifies the cloud-init configuration format. The default depends on the configured operating system type (`ostype`. We use the `nocloud` format for Linux, and `configdrive2` for windows.',
41cd94a0
WB
705 enum => ['configdrive2', 'nocloud'],
706 },
7b42f951
WB
707 ciuser => {
708 optional => 1,
709 type => 'string',
710 description => "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
711 },
712 cipassword => {
713 optional => 1,
714 type => 'string',
1d1c4e1c 715 description => 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
7b42f951 716 },
cb702ebe
DL
717 cicustom => {
718 optional => 1,
719 type => 'string',
720 description => 'cloud-init: Specify custom files to replace the automatically generated ones at start.',
721 format => 'pve-qm-cicustom',
722 },
0c9a7596
AD
723 searchdomain => {
724 optional => 1,
725 type => 'string',
726 description => "cloud-init: Sets DNS search domains for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
727 },
728 nameserver => {
729 optional => 1,
730 type => 'string', format => 'address-list',
731 description => "cloud-init: Sets DNS server IP address for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
732 },
733 sshkeys => {
734 optional => 1,
735 type => 'string',
736 format => 'urlencoded',
1d1c4e1c 737 description => "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
0c9a7596 738 },
1e3baf05
DM
739};
740
741# what about other qemu settings ?
742#cpu => 'string',
743#machine => 'string',
744#fda => 'file',
745#fdb => 'file',
746#mtdblock => 'file',
747#sd => 'file',
748#pflash => 'file',
749#snapshot => 'bool',
750#bootp => 'file',
751##tftp => 'dir',
752##smb => 'dir',
753#kernel => 'file',
754#append => 'string',
755#initrd => 'file',
756##soundhw => 'string',
757
758while (my ($k, $v) = each %$confdesc) {
759 PVE::JSONSchema::register_standard_option("pve-qm-$k", $v);
760}
761
1e3baf05 762my $MAX_USB_DEVICES = 5;
5bdcf937 763my $MAX_NETS = 32;
c4e16381 764my $MAX_HOSTPCI_DEVICES = 16;
bae179aa 765my $MAX_SERIAL_PORTS = 4;
1989a89c 766my $MAX_PARALLEL_PORTS = 3;
2ed5d572
AD
767my $MAX_NUMA = 8;
768
ffc0d8c7
WB
769my $numa_fmt = {
770 cpus => {
771 type => "string",
772 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
52261945 773 description => "CPUs accessing this NUMA node.",
ffc0d8c7
WB
774 format_description => "id[-id];...",
775 },
776 memory => {
777 type => "number",
52261945 778 description => "Amount of memory this NUMA node provides.",
ffc0d8c7
WB
779 optional => 1,
780 },
781 hostnodes => {
782 type => "string",
783 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
52261945 784 description => "Host NUMA nodes to use.",
ffc0d8c7
WB
785 format_description => "id[-id];...",
786 optional => 1,
787 },
788 policy => {
789 type => 'string',
790 enum => [qw(preferred bind interleave)],
52261945 791 description => "NUMA allocation policy.",
ffc0d8c7
WB
792 optional => 1,
793 },
794};
795PVE::JSONSchema::register_format('pve-qm-numanode', $numa_fmt);
2ed5d572
AD
796my $numadesc = {
797 optional => 1,
ffc0d8c7 798 type => 'string', format => $numa_fmt,
52261945 799 description => "NUMA topology.",
2ed5d572
AD
800};
801PVE::JSONSchema::register_standard_option("pve-qm-numanode", $numadesc);
802
803for (my $i = 0; $i < $MAX_NUMA; $i++) {
804 $confdesc->{"numa$i"} = $numadesc;
805}
1e3baf05
DM
806
807my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
55034103
KT
808 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
809 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
6b64503e 810my $nic_model_list_txt = join(' ', sort @$nic_model_list);
1e3baf05 811
52261945
DM
812my $net_fmt_bridge_descr = <<__EOD__;
813Bridge to attach the network device to. The Proxmox VE standard bridge
814is called 'vmbr0'.
815
816If you do not specify a bridge, we create a kvm user (NATed) network
817device, which provides DHCP and DNS services. The following addresses
818are used:
819
820 10.0.2.2 Gateway
821 10.0.2.3 DNS Server
822 10.0.2.4 SMB Server
823
824The DHCP server assign addresses to the guest starting from 10.0.2.15.
825__EOD__
826
cd9c34d1 827my $net_fmt = {
399d96db 828 macaddr => get_standard_option('mac-addr', {
52261945 829 description => "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
399d96db 830 }),
7f694a71
DM
831 model => {
832 type => 'string',
52261945 833 description => "Network Card Model. The 'virtio' model provides the best performance with very low CPU overhead. If your guest does not support this driver, it is usually best to use 'e1000'.",
7f694a71
DM
834 enum => $nic_model_list,
835 default_key => 1,
836 },
837 (map { $_ => { keyAlias => 'model', alias => 'macaddr' }} @$nic_model_list),
cd9c34d1
WB
838 bridge => {
839 type => 'string',
52261945 840 description => $net_fmt_bridge_descr,
cd9c34d1
WB
841 format_description => 'bridge',
842 optional => 1,
843 },
844 queues => {
845 type => 'integer',
846 minimum => 0, maximum => 16,
847 description => 'Number of packet queues to be used on the device.',
cd9c34d1
WB
848 optional => 1,
849 },
850 rate => {
851 type => 'number',
852 minimum => 0,
52261945 853 description => "Rate limit in mbps (megabytes per second) as floating point number.",
cd9c34d1
WB
854 optional => 1,
855 },
856 tag => {
857 type => 'integer',
9f41a659 858 minimum => 1, maximum => 4094,
cd9c34d1 859 description => 'VLAN tag to apply to packets on this interface.',
cd9c34d1
WB
860 optional => 1,
861 },
862 trunks => {
863 type => 'string',
864 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
865 description => 'VLAN trunks to pass through this interface.',
7f694a71 866 format_description => 'vlanid[;vlanid...]',
cd9c34d1
WB
867 optional => 1,
868 },
869 firewall => {
870 type => 'boolean',
871 description => 'Whether this interface should be protected by the firewall.',
cd9c34d1
WB
872 optional => 1,
873 },
874 link_down => {
875 type => 'boolean',
52261945 876 description => 'Whether this interface should be disconnected (like pulling the plug).',
cd9c34d1
WB
877 optional => 1,
878 },
879};
52261945 880
1e3baf05
DM
881my $netdesc = {
882 optional => 1,
7f694a71 883 type => 'string', format => $net_fmt,
52261945 884 description => "Specify network devices.",
1e3baf05 885};
52261945 886
1e3baf05
DM
887PVE::JSONSchema::register_standard_option("pve-qm-net", $netdesc);
888
0c9a7596
AD
889my $ipconfig_fmt = {
890 ip => {
891 type => 'string',
892 format => 'pve-ipv4-config',
893 format_description => 'IPv4Format/CIDR',
894 description => 'IPv4 address in CIDR format.',
895 optional => 1,
896 default => 'dhcp',
897 },
898 gw => {
899 type => 'string',
900 format => 'ipv4',
901 format_description => 'GatewayIPv4',
902 description => 'Default gateway for IPv4 traffic.',
903 optional => 1,
904 requires => 'ip',
905 },
906 ip6 => {
907 type => 'string',
908 format => 'pve-ipv6-config',
909 format_description => 'IPv6Format/CIDR',
910 description => 'IPv6 address in CIDR format.',
911 optional => 1,
912 default => 'dhcp',
913 },
914 gw6 => {
915 type => 'string',
916 format => 'ipv6',
917 format_description => 'GatewayIPv6',
918 description => 'Default gateway for IPv6 traffic.',
919 optional => 1,
920 requires => 'ip6',
921 },
922};
923PVE::JSONSchema::register_format('pve-qm-ipconfig', $ipconfig_fmt);
924my $ipconfigdesc = {
925 optional => 1,
926 type => 'string', format => 'pve-qm-ipconfig',
927 description => <<'EODESCR',
928cloud-init: Specify IP addresses and gateways for the corresponding interface.
929
930IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
931
932The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
933For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
934
935If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
936EODESCR
937};
938PVE::JSONSchema::register_standard_option("pve-qm-ipconfig", $netdesc);
939
1e3baf05
DM
940for (my $i = 0; $i < $MAX_NETS; $i++) {
941 $confdesc->{"net$i"} = $netdesc;
9ed7a77c
WB
942 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
943}
944
945foreach my $key (keys %$confdesc_cloudinit) {
946 $confdesc->{$key} = $confdesc_cloudinit->{$key};
1e3baf05
DM
947}
948
ffa42b86
DC
949PVE::JSONSchema::register_format('pve-volume-id-or-qm-path', \&verify_volume_id_or_qm_path);
950sub verify_volume_id_or_qm_path {
822c8a07
WB
951 my ($volid, $noerr) = @_;
952
ffa42b86
DC
953 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m|^/|) {
954 return $volid;
955 }
956
957 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
822c8a07
WB
958 $volid = eval { PVE::JSONSchema::check_format('pve-volume-id', $volid, '') };
959 if ($@) {
960 return undef if $noerr;
961 die $@;
962 }
963 return $volid;
964}
965
ff6ffe20 966my $usb_fmt = {
a6b9aee4
DC
967 host => {
968 default_key => 1,
969 type => 'string', format => 'pve-qm-usb-device',
970 format_description => 'HOSTUSBDEVICE|spice',
52261945
DM
971 description => <<EODESCR,
972The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
973
974 'bus-port(.port)*' (decimal numbers) or
975 'vendor_id:product_id' (hexadeciaml numbers) or
976 'spice'
977
978You can use the 'lsusb -t' command to list existing usb devices.
979
980NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
981
982The value 'spice' can be used to add a usb redirection devices for spice.
983EODESCR
a6b9aee4
DC
984 },
985 usb3 => {
986 optional => 1,
987 type => 'boolean',
97ef5356 988 description => "Specifies whether if given host option is a USB3 device or port.",
52261945 989 default => 0,
a6b9aee4
DC
990 },
991};
992
1e3baf05
DM
993my $usbdesc = {
994 optional => 1,
ff6ffe20 995 type => 'string', format => $usb_fmt,
52261945 996 description => "Configure an USB device (n is 0 to 4).",
1e3baf05
DM
997};
998PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
999
70740c1a 1000my $PCIRE = qr/([a-f0-9]{4}:)?[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
1f4f447b
WB
1001my $hostpci_fmt = {
1002 host => {
1003 default_key => 1,
1004 type => 'string',
1005 pattern => qr/$PCIRE(;$PCIRE)*/,
1006 format_description => 'HOSTPCIID[;HOSTPCIID2...]',
52261945 1007 description => <<EODESCR,
370b05e7 1008Host PCI device pass through. The PCI ID of a host's PCI device or a list
52261945
DM
1009of PCI virtual functions of the host. HOSTPCIID syntax is:
1010
1011'bus:dev.func' (hexadecimal numbers)
1012
1013You can us the 'lspci' command to list existing PCI devices.
52261945 1014EODESCR
1f4f447b
WB
1015 },
1016 rombar => {
1017 type => 'boolean',
52261945 1018 description => "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1f4f447b
WB
1019 optional => 1,
1020 default => 1,
1021 },
456a6fec
AD
1022 romfile => {
1023 type => 'string',
1024 pattern => '[^,;]+',
1025 format_description => 'string',
1026 description => "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1027 optional => 1,
1028 },
1f4f447b
WB
1029 pcie => {
1030 type => 'boolean',
52261945 1031 description => "Choose the PCI-express bus (needs the 'q35' machine model).",
1f4f447b
WB
1032 optional => 1,
1033 default => 0,
1034 },
1035 'x-vga' => {
1036 type => 'boolean',
52261945 1037 description => "Enable vfio-vga device support.",
1f4f447b
WB
1038 optional => 1,
1039 default => 0,
1040 },
6ab45bd7
DC
1041 'mdev' => {
1042 type => 'string',
1043 format_description => 'string',
1044 pattern => '[^/\.:]+',
1045 optional => 1,
1046 description => <<EODESCR
1047The type of mediated device to use.
1048An instance of this type will be created on startup of the VM and
1049will be cleaned up when the VM stops.
1050EODESCR
1051 }
1f4f447b
WB
1052};
1053PVE::JSONSchema::register_format('pve-qm-hostpci', $hostpci_fmt);
1054
040b06b7
DA
1055my $hostpcidesc = {
1056 optional => 1,
1057 type => 'string', format => 'pve-qm-hostpci',
52261945 1058 description => "Map host PCI devices into guest.",
faab5306
DM
1059 verbose_description => <<EODESCR,
1060Map host PCI devices into guest.
1061
370b05e7 1062NOTE: This option allows direct access to host hardware. So it is no longer
faab5306
DM
1063possible to migrate such machines - use with special care.
1064
1065CAUTION: Experimental! User reported problems with this option.
1066EODESCR
040b06b7
DA
1067};
1068PVE::JSONSchema::register_standard_option("pve-qm-hostpci", $hostpcidesc);
1069
bae179aa
DA
1070my $serialdesc = {
1071 optional => 1,
ca0cef26 1072 type => 'string',
1b0b51ed 1073 pattern => '(/dev/.+|socket)',
52261945
DM
1074 description => "Create a serial device inside the VM (n is 0 to 3)",
1075 verbose_description => <<EODESCR,
52261945
DM
1076Create a serial device inside the VM (n is 0 to 3), and pass through a
1077host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1078host side (use 'qm terminal' to open a terminal connection).
bae179aa 1079
8a61e0fd 1080NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
bae179aa 1081
52261945 1082CAUTION: Experimental! User reported problems with this option.
bae179aa
DA
1083EODESCR
1084};
bae179aa 1085
1989a89c
DA
1086my $paralleldesc= {
1087 optional => 1,
ca0cef26 1088 type => 'string',
9ecc8431 1089 pattern => '/dev/parport\d+|/dev/usb/lp\d+',
52261945
DM
1090 description => "Map host parallel devices (n is 0 to 2).",
1091 verbose_description => <<EODESCR,
19672434 1092Map host parallel devices (n is 0 to 2).
1989a89c 1093
8a61e0fd 1094NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1989a89c 1095
52261945 1096CAUTION: Experimental! User reported problems with this option.
1989a89c
DA
1097EODESCR
1098};
1989a89c
DA
1099
1100for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1101 $confdesc->{"parallel$i"} = $paralleldesc;
1102}
1103
bae179aa
DA
1104for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1105 $confdesc->{"serial$i"} = $serialdesc;
1106}
1107
040b06b7
DA
1108for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1109 $confdesc->{"hostpci$i"} = $hostpcidesc;
1110}
1e3baf05 1111
e0fd2b2f
FE
1112for my $key (keys %{$PVE::QemuServer::Drive::drivedesc_hash}) {
1113 $confdesc->{$key} = $PVE::QemuServer::Drive::drivedesc_hash->{$key};
cdb0931f
DA
1114}
1115
1e3baf05
DM
1116for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1117 $confdesc->{"usb$i"} = $usbdesc;
1118}
1119
1e3baf05
DM
1120my $kvm_api_version = 0;
1121
1122sub kvm_version {
1e3baf05
DM
1123 return $kvm_api_version if $kvm_api_version;
1124
646f2df4
WB
1125 open my $fh, '<', '/dev/kvm'
1126 or return undef;
1e3baf05 1127
646f2df4
WB
1128 # 0xae00 => KVM_GET_API_VERSION
1129 $kvm_api_version = ioctl($fh, 0xae00, 0);
1e3baf05 1130
646f2df4 1131 return $kvm_api_version;
1e3baf05
DM
1132}
1133
1476b99f
DC
1134my $kvm_user_version = {};
1135my $kvm_mtime = {};
1e3baf05
DM
1136
1137sub kvm_user_version {
1476b99f 1138 my ($binary) = @_;
1e3baf05 1139
1476b99f
DC
1140 $binary //= get_command_for_arch(get_host_arch()); # get the native arch by default
1141 my $st = stat($binary);
1e3baf05 1142
1476b99f
DC
1143 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1144 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1145 $cachedmtime == $st->mtime;
1146
1147 $kvm_user_version->{$binary} = 'unknown';
1148 $kvm_mtime->{$binary} = $st->mtime;
1e3baf05 1149
09b11429
TL
1150 my $code = sub {
1151 my $line = shift;
1152 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1476b99f 1153 $kvm_user_version->{$binary} = $2;
09b11429
TL
1154 }
1155 };
19672434 1156
1476b99f 1157 eval { run_command([$binary, '--version'], outfunc => $code); };
09b11429 1158 warn $@ if $@;
1e3baf05 1159
1476b99f 1160 return $kvm_user_version->{$binary};
1e3baf05
DM
1161
1162}
1163
db70021b
TL
1164sub kernel_has_vhost_net {
1165 return -c '/dev/vhost-net';
1166}
1e3baf05 1167
1e3baf05
DM
1168sub option_exists {
1169 my $key = shift;
1170 return defined($confdesc->{$key});
19672434 1171}
1e3baf05 1172
1e3baf05 1173my $cdrom_path;
1e3baf05
DM
1174sub get_cdrom_path {
1175
1176 return $cdrom_path if $cdrom_path;
1177
1178 return $cdrom_path = "/dev/cdrom" if -l "/dev/cdrom";
1179 return $cdrom_path = "/dev/cdrom1" if -l "/dev/cdrom1";
1180 return $cdrom_path = "/dev/cdrom2" if -l "/dev/cdrom2";
1181}
1182
1183sub get_iso_path {
1184 my ($storecfg, $vmid, $cdrom) = @_;
1185
1186 if ($cdrom eq 'cdrom') {
1187 return get_cdrom_path();
1188 } elsif ($cdrom eq 'none') {
1189 return '';
1190 } elsif ($cdrom =~ m|^/|) {
1191 return $cdrom;
1192 } else {
6b64503e 1193 return PVE::Storage::path($storecfg, $cdrom);
1e3baf05
DM
1194 }
1195}
1196
1197# try to convert old style file names to volume IDs
1198sub filename_to_volume_id {
1199 my ($vmid, $file, $media) = @_;
1200
0c9a7596 1201 if (!($file eq 'none' || $file eq 'cdrom' ||
1e3baf05 1202 $file =~ m|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
19672434 1203
1e3baf05 1204 return undef if $file =~ m|/|;
19672434 1205
1e3baf05
DM
1206 if ($media && $media eq 'cdrom') {
1207 $file = "local:iso/$file";
1208 } else {
1209 $file = "local:$vmid/$file";
1210 }
1211 }
1212
1213 return $file;
1214}
1215
1216sub verify_media_type {
1217 my ($opt, $vtype, $media) = @_;
1218
1219 return if !$media;
1220
1221 my $etype;
1222 if ($media eq 'disk') {
a125592c 1223 $etype = 'images';
1e3baf05
DM
1224 } elsif ($media eq 'cdrom') {
1225 $etype = 'iso';
1226 } else {
1227 die "internal error";
1228 }
1229
1230 return if ($vtype eq $etype);
19672434 1231
1e3baf05
DM
1232 raise_param_exc({ $opt => "unexpected media type ($vtype != $etype)" });
1233}
1234
1235sub cleanup_drive_path {
1236 my ($opt, $storecfg, $drive) = @_;
1237
1238 # try to convert filesystem paths to volume IDs
1239
1240 if (($drive->{file} !~ m/^(cdrom|none)$/) &&
1241 ($drive->{file} !~ m|^/dev/.+|) &&
1242 ($drive->{file} !~ m/^([^:]+):(.+)$/) &&
19672434 1243 ($drive->{file} !~ m/^\d+$/)) {
1e3baf05
DM
1244 my ($vtype, $volid) = PVE::Storage::path_to_volume_id($storecfg, $drive->{file});
1245 raise_param_exc({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1246 $drive->{media} = 'cdrom' if !$drive->{media} && $vtype eq 'iso';
1247 verify_media_type($opt, $vtype, $drive->{media});
1248 $drive->{file} = $volid;
1249 }
1250
1251 $drive->{media} = 'cdrom' if !$drive->{media} && $drive->{file} =~ m/^(cdrom|none)$/;
1252}
1253
b3c2bdd1
DM
1254sub parse_hotplug_features {
1255 my ($data) = @_;
1256
1257 my $res = {};
1258
1259 return $res if $data eq '0';
a1b7d579 1260
b3c2bdd1
DM
1261 $data = $confdesc->{hotplug}->{default} if $data eq '1';
1262
45827685 1263 foreach my $feature (PVE::Tools::split_list($data)) {
b3c2bdd1
DM
1264 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1265 $res->{$1} = 1;
1266 } else {
596a0a20 1267 die "invalid hotplug feature '$feature'\n";
b3c2bdd1
DM
1268 }
1269 }
1270 return $res;
1271}
1272
1273PVE::JSONSchema::register_format('pve-hotplug-features', \&pve_verify_hotplug_features);
1274sub pve_verify_hotplug_features {
1275 my ($value, $noerr) = @_;
1276
1277 return $value if parse_hotplug_features($value);
1278
1279 return undef if $noerr;
1280
1281 die "unable to parse hotplug option\n";
1282}
1283
28ef82d3
DM
1284sub scsi_inquiry {
1285 my($fh, $noerr) = @_;
1286
1287 my $SG_IO = 0x2285;
1288 my $SG_GET_VERSION_NUM = 0x2282;
1289
1290 my $versionbuf = "\x00" x 8;
1291 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1292 if (!$ret) {
1293 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1294 return undef;
1295 }
97d62eb7 1296 my $version = unpack("I", $versionbuf);
28ef82d3
DM
1297 if ($version < 30000) {
1298 die "scsi generic interface too old\n" if !$noerr;
1299 return undef;
1300 }
97d62eb7 1301
28ef82d3
DM
1302 my $buf = "\x00" x 36;
1303 my $sensebuf = "\x00" x 8;
f334aa3e 1304 my $cmd = pack("C x3 C x1", 0x12, 36);
97d62eb7 1305
28ef82d3
DM
1306 # see /usr/include/scsi/sg.h
1307 my $sg_io_hdr_t = "i i C C s I P P P I I i P C C C C S S i I I";
1308
97d62eb7
DM
1309 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1310 length($sensebuf), 0, length($buf), $buf,
28ef82d3
DM
1311 $cmd, $sensebuf, 6000);
1312
1313 $ret = ioctl($fh, $SG_IO, $packet);
1314 if (!$ret) {
1315 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1316 return undef;
1317 }
97d62eb7 1318
28ef82d3
DM
1319 my @res = unpack($sg_io_hdr_t, $packet);
1320 if ($res[17] || $res[18]) {
1321 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1322 return undef;
1323 }
1324
1325 my $res = {};
09984754 1326 (my $byte0, my $byte1, $res->{vendor},
28ef82d3
DM
1327 $res->{product}, $res->{revision}) = unpack("C C x6 A8 A16 A4", $buf);
1328
09984754
DM
1329 $res->{removable} = $byte1 & 128 ? 1 : 0;
1330 $res->{type} = $byte0 & 31;
1331
28ef82d3
DM
1332 return $res;
1333}
1334
1335sub path_is_scsi {
1336 my ($path) = @_;
1337
1338 my $fh = IO::File->new("+<$path") || return undef;
1339 my $res = scsi_inquiry($fh, 1);
1340 close($fh);
1341
1342 return $res;
1343}
1344
db656e5f 1345sub print_tabletdevice_full {
d559309f 1346 my ($conf, $arch) = @_;
b467f79a 1347
3392d6ca 1348 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
db656e5f
DM
1349
1350 # we use uhci for old VMs because tablet driver was buggy in older qemu
d559309f 1351 my $usbbus;
3392d6ca 1352 if (PVE::QemuServer::Machine::machine_type_is_q35($conf) || $arch eq 'aarch64') {
d559309f
WB
1353 $usbbus = 'ehci';
1354 } else {
1355 $usbbus = 'uhci';
1356 }
b467f79a 1357
db656e5f
DM
1358 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1359}
1360
d559309f
WB
1361sub print_keyboarddevice_full {
1362 my ($conf, $arch, $machine) = @_;
1363
1364 return undef if $arch ne 'aarch64';
1365
1366 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1367}
1368
ca916ecc 1369sub print_drivedevice_full {
d559309f 1370 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
ca916ecc
DA
1371
1372 my $device = '';
1373 my $maxdev = 0;
19672434 1374
ca916ecc 1375 if ($drive->{interface} eq 'virtio') {
d559309f 1376 my $pciaddr = print_pci_addr("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
2ed36a41 1377 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
51f492cd 1378 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread};
2ed36a41 1379 } elsif ($drive->{interface} eq 'scsi') {
6731a4cf 1380
ee034f5c 1381 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
2ed36a41
DM
1382 my $unit = $drive->{index} % $maxdev;
1383 my $devicetype = 'hd';
69bcf246
WB
1384 my $path = '';
1385 if (drive_is_cdrom($drive)) {
1386 $devicetype = 'cd';
29b19529 1387 } else {
69bcf246
WB
1388 if ($drive->{file} =~ m|^/|) {
1389 $path = $drive->{file};
1390 if (my $info = path_is_scsi($path)) {
8e3c33ab 1391 if ($info->{type} == 0 && $drive->{scsiblock}) {
69bcf246
WB
1392 $devicetype = 'block';
1393 } elsif ($info->{type} == 1) { # tape
1394 $devicetype = 'generic';
1395 }
1396 }
1397 } else {
1398 $path = PVE::Storage::path($storecfg, $drive->{file});
1399 }
1400
a034e3d6 1401 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
9471e48b 1402 my $version = PVE::QemuServer::Machine::extract_version($machine_type, kvm_user_version());
a034e3d6 1403 if ($path =~ m/^iscsi\:\/\// &&
2ea5fb7e 1404 !min_version($version, 4, 1)) {
69bcf246
WB
1405 $devicetype = 'generic';
1406 }
1407 }
1408
1409 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)){
1410 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1411 } else {
1412 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0,lun=$drive->{index},drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1413 }
cdd20088 1414
6c875f9f
NC
1415 if ($drive->{ssd} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1416 $device .= ",rotation_rate=1";
1417 }
e741c516 1418 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn};
6c875f9f
NC
1419
1420 } elsif ($drive->{interface} eq 'ide' || $drive->{interface} eq 'sata') {
e0fd2b2f 1421 my $maxdev = ($drive->{interface} eq 'sata') ? $PVE::QemuServer::Drive::MAX_SATA_DISKS : 2;
2ed36a41
DM
1422 my $controller = int($drive->{index} / $maxdev);
1423 my $unit = $drive->{index} % $maxdev;
1424 my $devicetype = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd";
1425
6c875f9f
NC
1426 $device = "ide-$devicetype";
1427 if ($drive->{interface} eq 'ide') {
1428 $device .= ",bus=ide.$controller,unit=$unit";
1429 } else {
1430 $device .= ",bus=ahci$controller.$unit";
1431 }
1432 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1433
1434 if ($devicetype eq 'hd') {
1435 if (my $model = $drive->{model}) {
1436 $model = URI::Escape::uri_unescape($model);
1437 $device .= ",model=$model";
1438 }
1439 if ($drive->{ssd}) {
1440 $device .= ",rotation_rate=1";
1441 }
0f2812c2 1442 }
e741c516 1443 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn};
2ed36a41
DM
1444 } elsif ($drive->{interface} eq 'usb') {
1445 die "implement me";
1446 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1447 } else {
1448 die "unsupported interface type";
ca916ecc
DA
1449 }
1450
3b408e82
DM
1451 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex};
1452
a70e7e6c
TL
1453 if (my $serial = $drive->{serial}) {
1454 $serial = URI::Escape::uri_unescape($serial);
1455 $device .= ",serial=$serial";
1456 }
1457
1458
ca916ecc
DA
1459 return $device;
1460}
1461
15b21acc 1462sub get_initiator_name {
46f58b5f 1463 my $initiator;
15b21acc 1464
46f58b5f
DM
1465 my $fh = IO::File->new('/etc/iscsi/initiatorname.iscsi') || return undef;
1466 while (defined(my $line = <$fh>)) {
1467 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
15b21acc
MR
1468 $initiator = $1;
1469 last;
1470 }
46f58b5f
DM
1471 $fh->close();
1472
15b21acc
MR
1473 return $initiator;
1474}
1475
776c5f50 1476sub print_drive_commandline_full {
1e3baf05
DM
1477 my ($storecfg, $vmid, $drive) = @_;
1478
d81f0f09
DM
1479 my $path;
1480 my $volid = $drive->{file};
1481 my $format;
370b05e7 1482
d81f0f09
DM
1483 if (drive_is_cdrom($drive)) {
1484 $path = get_iso_path($storecfg, $vmid, $volid);
1485 } else {
1486 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
1487 if ($storeid) {
1488 $path = PVE::Storage::path($storecfg, $volid);
1489 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
1490 $format = qemu_img_format($scfg, $volname);
1491 } else {
1492 $path = $volid;
5b61bff2 1493 $format = "raw";
d81f0f09
DM
1494 }
1495 }
1496
1e3baf05 1497 my $opts = '';
8a267708 1498 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1e3baf05 1499 foreach my $o (@qemu_drive_options) {
5fc74861 1500 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
19672434 1501 }
8a267708
DC
1502
1503 # snapshot only accepts on|off
1504 if (defined($drive->{snapshot})) {
1505 my $v = $drive->{snapshot} ? 'on' : 'off';
1506 $opts .= ",snapshot=$v";
1507 }
1508
fb8e95a2
WB
1509 foreach my $type (['', '-total'], [_rd => '-read'], [_wr => '-write']) {
1510 my ($dir, $qmpname) = @$type;
1511 if (my $v = $drive->{"mbps$dir"}) {
1512 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1513 }
1514 if (my $v = $drive->{"mbps${dir}_max"}) {
1515 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1516 }
1517 if (my $v = $drive->{"bps${dir}_max_length"}) {
1518 $opts .= ",throttling.bps$qmpname-max-length=$v";
1519 }
1520 if (my $v = $drive->{"iops${dir}"}) {
1521 $opts .= ",throttling.iops$qmpname=$v";
1522 }
1523 if (my $v = $drive->{"iops${dir}_max"}) {
8aca1654 1524 $opts .= ",throttling.iops$qmpname-max=$v";
fb8e95a2
WB
1525 }
1526 if (my $v = $drive->{"iops${dir}_max_length"}) {
8aca1654 1527 $opts .= ",throttling.iops$qmpname-max-length=$v";
fb8e95a2
WB
1528 }
1529 }
1530
d81f0f09
DM
1531 $opts .= ",format=$format" if $format && !$drive->{format};
1532
b2ee900e
WB
1533 my $cache_direct = 0;
1534
1535 if (my $cache = $drive->{cache}) {
1536 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1537 } elsif (!drive_is_cdrom($drive)) {
1538 $opts .= ",cache=none";
1539 $cache_direct = 1;
1540 }
1541
1542 # aio native works only with O_DIRECT
1543 if (!$drive->{aio}) {
1544 if($cache_direct) {
1545 $opts .= ",aio=native";
1546 } else {
1547 $opts .= ",aio=threads";
1548 }
1549 }
11490cf2 1550
6e47c3b4
WB
1551 if (!drive_is_cdrom($drive)) {
1552 my $detectzeroes;
7d4e30f3 1553 if (defined($drive->{detect_zeroes}) && !$drive->{detect_zeroes}) {
6e47c3b4
WB
1554 $detectzeroes = 'off';
1555 } elsif ($drive->{discard}) {
1556 $detectzeroes = $drive->{discard} eq 'on' ? 'unmap' : 'on';
1557 } else {
1558 # This used to be our default with discard not being specified:
1559 $detectzeroes = 'on';
1560 }
1561 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1562 }
f1e05305 1563
1e3baf05
DM
1564 my $pathinfo = $path ? "file=$path," : '';
1565
3ebfcc86 1566 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1e3baf05
DM
1567}
1568
cc4d6182 1569sub print_netdevice_full {
d559309f 1570 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
cc4d6182
DA
1571
1572 my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
1573
1574 my $device = $net->{model};
1575 if ($net->{model} eq 'virtio') {
1576 $device = 'virtio-net-pci';
1577 };
1578
d559309f 1579 my $pciaddr = print_pci_addr("$netid", $bridges, $arch, $machine_type);
5e2068d2 1580 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
a9410357
AD
1581 if ($net->{queues} && $net->{queues} > 1 && $net->{model} eq 'virtio'){
1582 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1583 my $vectors = $net->{queues} * 2 + 2;
1584 $tmpstr .= ",vectors=$vectors,mq=on";
1585 }
cc4d6182 1586 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex} ;
ba9e1000
DM
1587
1588 if ($use_old_bios_files) {
1589 my $romfile;
1590 if ($device eq 'virtio-net-pci') {
1591 $romfile = 'pxe-virtio.rom';
1592 } elsif ($device eq 'e1000') {
1593 $romfile = 'pxe-e1000.rom';
1594 } elsif ($device eq 'ne2k') {
1595 $romfile = 'pxe-ne2k_pci.rom';
1596 } elsif ($device eq 'pcnet') {
1597 $romfile = 'pxe-pcnet.rom';
1598 } elsif ($device eq 'rtl8139') {
1599 $romfile = 'pxe-rtl8139.rom';
1600 }
1601 $tmpstr .= ",romfile=$romfile" if $romfile;
1602 }
1603
cc4d6182
DA
1604 return $tmpstr;
1605}
1606
1607sub print_netdev_full {
d559309f 1608 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
cc4d6182
DA
1609
1610 my $i = '';
1611 if ($netid =~ m/^net(\d+)$/) {
1612 $i = int($1);
1613 }
1614
1615 die "got strange net id '$i'\n" if $i >= ${MAX_NETS};
1616
1617 my $ifname = "tap${vmid}i$i";
1618
1619 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1620 die "interface name '$ifname' is too long (max 15 character)\n"
1621 if length($ifname) >= 16;
1622
1623 my $vhostparam = '';
6f0cb675 1624 if (is_native($arch)) {
db70021b 1625 $vhostparam = ',vhost=on' if kernel_has_vhost_net() && $net->{model} eq 'virtio';
6f0cb675 1626 }
cc4d6182
DA
1627
1628 my $vmname = $conf->{name} || "vm$vmid";
1629
a9410357 1630 my $netdev = "";
208ba94e 1631 my $script = $hotplug ? "pve-bridge-hotplug" : "pve-bridge";
a9410357 1632
cc4d6182 1633 if ($net->{bridge}) {
208ba94e 1634 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
cc4d6182 1635 } else {
a9410357 1636 $netdev = "type=user,id=$netid,hostname=$vmname";
cc4d6182 1637 }
a9410357
AD
1638
1639 $netdev .= ",queues=$net->{queues}" if ($net->{queues} && $net->{model} eq 'virtio');
1640
1641 return $netdev;
cc4d6182 1642}
1e3baf05 1643
55655ebc
DC
1644my $vga_map = {
1645 'cirrus' => 'cirrus-vga',
1646 'std' => 'VGA',
1647 'vmware' => 'vmware-svga',
1648 'virtio' => 'virtio-vga',
1649};
1650
1651sub print_vga_device {
2ea5fb7e 1652 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
55655ebc
DC
1653
1654 my $type = $vga_map->{$vga->{type}};
86c9fafe 1655 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
d559309f
WB
1656 $type = 'virtio-gpu';
1657 }
55655ebc 1658 my $vgamem_mb = $vga->{memory};
6021c7a5
AL
1659
1660 my $max_outputs = '';
55655ebc
DC
1661 if ($qxlnum) {
1662 $type = $id ? 'qxl' : 'qxl-vga';
6021c7a5 1663
c5a4c92c 1664 if (!$conf->{ostype} || $conf->{ostype} =~ m/^(?:l\d\d)|(?:other)$/) {
6021c7a5 1665 # set max outputs so linux can have up to 4 qxl displays with one device
2ea5fb7e 1666 if (min_version($machine_version, 4, 1)) {
9e8976ea
TL
1667 $max_outputs = ",max_outputs=4";
1668 }
6021c7a5 1669 }
55655ebc 1670 }
6021c7a5 1671
55655ebc
DC
1672 die "no devicetype for $vga->{type}\n" if !$type;
1673
1674 my $memory = "";
1675 if ($vgamem_mb) {
1676 if ($vga->{type} eq 'virtio') {
1677 my $bytes = PVE::Tools::convert_size($vgamem_mb, "mb" => "b");
1678 $memory = ",max_hostmem=$bytes";
1679 } elsif ($qxlnum) {
1680 # from https://www.spice-space.org/multiple-monitors.html
1681 $memory = ",vgamem_mb=$vga->{memory}";
1682 my $ram = $vgamem_mb * 4;
1683 my $vram = $vgamem_mb * 2;
1684 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1685 } else {
1686 $memory = ",vgamem_mb=$vga->{memory}";
1687 }
1688 } elsif ($qxlnum && $id) {
1689 $memory = ",ram_size=67108864,vram_size=33554432";
1690 }
1691
3392d6ca 1692 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
55655ebc
DC
1693 my $vgaid = "vga" . ($id // '');
1694 my $pciaddr;
daadd5a4 1695
55655ebc 1696 if ($q35 && $vgaid eq 'vga') {
daadd5a4 1697 # the first display uses pcie.0 bus on q35 machines
d559309f 1698 $pciaddr = print_pcie_addr($vgaid, $bridges, $arch, $machine);
55655ebc 1699 } else {
d559309f 1700 $pciaddr = print_pci_addr($vgaid, $bridges, $arch, $machine);
55655ebc
DC
1701 }
1702
6021c7a5 1703 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}";
55655ebc
DC
1704}
1705
ffc0d8c7
WB
1706sub parse_number_sets {
1707 my ($set) = @_;
1708 my $res = [];
1709 foreach my $part (split(/;/, $set)) {
1710 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1711 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1712 push @$res, [ $1, $2 ];
2ed5d572 1713 } else {
ffc0d8c7 1714 die "invalid range: $part\n";
2ed5d572
AD
1715 }
1716 }
ffc0d8c7
WB
1717 return $res;
1718}
2ed5d572 1719
ffc0d8c7
WB
1720sub parse_numa {
1721 my ($data) = @_;
1722
1723 my $res = PVE::JSONSchema::parse_property_string($numa_fmt, $data);
1724 $res->{cpus} = parse_number_sets($res->{cpus}) if defined($res->{cpus});
1725 $res->{hostnodes} = parse_number_sets($res->{hostnodes}) if defined($res->{hostnodes});
2ed5d572
AD
1726 return $res;
1727}
1728
040b06b7
DA
1729sub parse_hostpci {
1730 my ($value) = @_;
1731
1732 return undef if !$value;
1733
1f4f447b 1734 my $res = PVE::JSONSchema::parse_property_string($hostpci_fmt, $value);
0cea6a01 1735
1f4f447b
WB
1736 my @idlist = split(/;/, $res->{host});
1737 delete $res->{host};
1738 foreach my $id (@idlist) {
844b55fb 1739 my $devs = PVE::SysFSTools::lspci($id);
c7728fdb 1740 die "no PCI device found for '$id'\n" if !scalar(@$devs);
844b55fb 1741 push @{$res->{pciid}}, @$devs;
040b06b7 1742 }
040b06b7
DA
1743 return $res;
1744}
1745
1e3baf05
DM
1746# netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1747sub parse_net {
1748 my ($data) = @_;
1749
cd9c34d1
WB
1750 my $res = eval { PVE::JSONSchema::parse_property_string($net_fmt, $data) };
1751 if ($@) {
1752 warn $@;
1753 return undef;
1e3baf05 1754 }
b5b99790
WB
1755 if (!defined($res->{macaddr})) {
1756 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
1757 $res->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
1758 }
0c9a7596
AD
1759 return $res;
1760}
1761
1762# ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1763sub parse_ipconfig {
1764 my ($data) = @_;
1765
1766 my $res = eval { PVE::JSONSchema::parse_property_string($ipconfig_fmt, $data) };
1767 if ($@) {
1768 warn $@;
1769 return undef;
1770 }
1771
1772 if ($res->{gw} && !$res->{ip}) {
1773 warn 'gateway specified without specifying an IP address';
1774 return undef;
1775 }
1776 if ($res->{gw6} && !$res->{ip6}) {
1777 warn 'IPv6 gateway specified without specifying an IPv6 address';
1778 return undef;
1779 }
1780 if ($res->{gw} && $res->{ip} eq 'dhcp') {
1781 warn 'gateway specified together with DHCP';
1782 return undef;
1783 }
1784 if ($res->{gw6} && $res->{ip6} !~ /^$IPV6RE/) {
1785 # gw6 + auto/dhcp
1786 warn "IPv6 gateway specified together with $res->{ip6} address";
1787 return undef;
1788 }
1789
1790 if (!$res->{ip} && !$res->{ip6}) {
1791 return { ip => 'dhcp', ip6 => 'dhcp' };
1792 }
1793
1e3baf05
DM
1794 return $res;
1795}
1796
1797sub print_net {
1798 my $net = shift;
1799
cd9c34d1 1800 return PVE::JSONSchema::print_property_string($net, $net_fmt);
1e3baf05
DM
1801}
1802
1803sub add_random_macs {
1804 my ($settings) = @_;
1805
1806 foreach my $opt (keys %$settings) {
1807 next if $opt !~ m/^net(\d+)$/;
1808 my $net = parse_net($settings->{$opt});
1809 next if !$net;
1810 $settings->{$opt} = print_net($net);
1811 }
1812}
1813
055d554d
DM
1814sub vm_is_volid_owner {
1815 my ($storecfg, $vmid, $volid) = @_;
1816
1817 if ($volid !~ m|^/|) {
1818 my ($path, $owner);
1819 eval { ($path, $owner) = PVE::Storage::path($storecfg, $volid); };
1820 if ($owner && ($owner == $vmid)) {
1821 return 1;
1822 }
1823 }
1824
1825 return undef;
1826}
1827
055d554d
DM
1828sub vmconfig_register_unused_drive {
1829 my ($storecfg, $vmid, $conf, $drive) = @_;
1830
2d9ddec5
WB
1831 if (drive_is_cloudinit($drive)) {
1832 eval { PVE::Storage::vdisk_free($storecfg, $drive->{file}) };
1833 warn $@ if $@;
1834 } elsif (!drive_is_cdrom($drive)) {
055d554d
DM
1835 my $volid = $drive->{file};
1836 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
8793d495 1837 PVE::QemuConfig->add_unused_volume($conf, $volid, $vmid);
055d554d
DM
1838 }
1839 }
1840}
1841
1f30ac3a 1842# smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
ff6ffe20 1843my $smbios1_fmt = {
bd27e851
WB
1844 uuid => {
1845 type => 'string',
1846 pattern => '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1847 format_description => 'UUID',
52261945 1848 description => "Set SMBIOS1 UUID.",
bd27e851
WB
1849 optional => 1,
1850 },
1851 version => {
1852 type => 'string',
1f30ac3a
CE
1853 pattern => '[A-Za-z0-9+\/]+={0,2}',
1854 format_description => 'Base64 encoded string',
52261945 1855 description => "Set SMBIOS1 version.",
bd27e851
WB
1856 optional => 1,
1857 },
1858 serial => {
1859 type => 'string',
1f30ac3a
CE
1860 pattern => '[A-Za-z0-9+\/]+={0,2}',
1861 format_description => 'Base64 encoded string',
52261945 1862 description => "Set SMBIOS1 serial number.",
bd27e851
WB
1863 optional => 1,
1864 },
1865 manufacturer => {
1866 type => 'string',
1f30ac3a
CE
1867 pattern => '[A-Za-z0-9+\/]+={0,2}',
1868 format_description => 'Base64 encoded string',
52261945 1869 description => "Set SMBIOS1 manufacturer.",
bd27e851
WB
1870 optional => 1,
1871 },
1872 product => {
1873 type => 'string',
1f30ac3a
CE
1874 pattern => '[A-Za-z0-9+\/]+={0,2}',
1875 format_description => 'Base64 encoded string',
52261945 1876 description => "Set SMBIOS1 product ID.",
bd27e851
WB
1877 optional => 1,
1878 },
1879 sku => {
1880 type => 'string',
1f30ac3a
CE
1881 pattern => '[A-Za-z0-9+\/]+={0,2}',
1882 format_description => 'Base64 encoded string',
52261945 1883 description => "Set SMBIOS1 SKU string.",
bd27e851
WB
1884 optional => 1,
1885 },
1886 family => {
1887 type => 'string',
1f30ac3a
CE
1888 pattern => '[A-Za-z0-9+\/]+={0,2}',
1889 format_description => 'Base64 encoded string',
52261945 1890 description => "Set SMBIOS1 family string.",
bd27e851
WB
1891 optional => 1,
1892 },
1f30ac3a
CE
1893 base64 => {
1894 type => 'boolean',
1895 description => 'Flag to indicate that the SMBIOS values are base64 encoded',
1896 optional => 1,
1897 },
2796e7d5
DM
1898};
1899
2796e7d5
DM
1900sub parse_smbios1 {
1901 my ($data) = @_;
1902
ff6ffe20 1903 my $res = eval { PVE::JSONSchema::parse_property_string($smbios1_fmt, $data) };
bd27e851 1904 warn $@ if $@;
2796e7d5
DM
1905 return $res;
1906}
1907
cd11416f
DM
1908sub print_smbios1 {
1909 my ($smbios1) = @_;
ff6ffe20 1910 return PVE::JSONSchema::print_property_string($smbios1, $smbios1_fmt);
cd11416f
DM
1911}
1912
ff6ffe20 1913PVE::JSONSchema::register_format('pve-qm-smbios1', $smbios1_fmt);
2796e7d5 1914
0ea9541d
DM
1915sub parse_watchdog {
1916 my ($value) = @_;
1917
1918 return undef if !$value;
1919
ec3582b5
WB
1920 my $res = eval { PVE::JSONSchema::parse_property_string($watchdog_fmt, $value) };
1921 warn $@ if $@;
0ea9541d
DM
1922 return $res;
1923}
1924
9d66b397
SI
1925sub parse_guest_agent {
1926 my ($value) = @_;
1927
1928 return {} if !defined($value->{agent});
1929
1930 my $res = eval { PVE::JSONSchema::parse_property_string($agent_fmt, $value->{agent}) };
1931 warn $@ if $@;
1932
1933 # if the agent is disabled ignore the other potentially set properties
1934 return {} if !$res->{enabled};
1935 return $res;
1936}
1937
55655ebc
DC
1938sub parse_vga {
1939 my ($value) = @_;
1940
1941 return {} if !$value;
1942 my $res = eval { PVE::JSONSchema::parse_property_string($vga_fmt, $value) };
1943 warn $@ if $@;
1944 return $res;
1945}
1946
2cf61f33
SR
1947sub parse_rng {
1948 my ($value) = @_;
1949
1950 return undef if !$value;
1951
1952 my $res = eval { PVE::JSONSchema::parse_property_string($rng_fmt, $value) };
1953 warn $@ if $@;
1954 return $res;
1955}
1956
1e3baf05
DM
1957PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
1958sub verify_usb_device {
1959 my ($value, $noerr) = @_;
1960
1961 return $value if parse_usb_device($value);
1962
1963 return undef if $noerr;
19672434 1964
1e3baf05
DM
1965 die "unable to parse usb device\n";
1966}
1967
1e3baf05
DM
1968# add JSON properties for create and set function
1969sub json_config_properties {
1970 my $prop = shift;
1971
1972 foreach my $opt (keys %$confdesc) {
c6737ef1 1973 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
1e3baf05
DM
1974 $prop->{$opt} = $confdesc->{$opt};
1975 }
1976
1977 return $prop;
1978}
1979
d41121fd
DM
1980# return copy of $confdesc_cloudinit to generate documentation
1981sub cloudinit_config_properties {
1982
1983 return dclone($confdesc_cloudinit);
1984}
1985
1e3baf05
DM
1986sub check_type {
1987 my ($key, $value) = @_;
1988
1989 die "unknown setting '$key'\n" if !$confdesc->{$key};
1990
1991 my $type = $confdesc->{$key}->{type};
1992
6b64503e 1993 if (!defined($value)) {
1e3baf05
DM
1994 die "got undefined value\n";
1995 }
1996
1997 if ($value =~ m/[\n\r]/) {
1998 die "property contains a line feed\n";
1999 }
2000
2001 if ($type eq 'boolean') {
19672434
DM
2002 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2003 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2004 die "type check ('boolean') failed - got '$value'\n";
1e3baf05
DM
2005 } elsif ($type eq 'integer') {
2006 return int($1) if $value =~ m/^(\d+)$/;
2007 die "type check ('integer') failed - got '$value'\n";
04432191
AD
2008 } elsif ($type eq 'number') {
2009 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2010 die "type check ('number') failed - got '$value'\n";
1e3baf05
DM
2011 } elsif ($type eq 'string') {
2012 if (my $fmt = $confdesc->{$key}->{format}) {
1e3baf05 2013 PVE::JSONSchema::check_format($fmt, $value);
19672434
DM
2014 return $value;
2015 }
1e3baf05 2016 $value =~ s/^\"(.*)\"$/$1/;
19672434 2017 return $value;
1e3baf05
DM
2018 } else {
2019 die "internal error"
2020 }
2021}
2022
1e3baf05 2023sub destroy_vm {
b04ea584 2024 my ($storecfg, $vmid, $skiplock, $replacement_conf) = @_;
1e3baf05 2025
ffda963f 2026 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 2027
ffda963f 2028 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 2029
5e67a2d2
DC
2030 if ($conf->{template}) {
2031 # check if any base image is still used by a linked clone
2032 foreach_drive($conf, sub {
2033 my ($ds, $drive) = @_;
5e67a2d2
DC
2034 return if drive_is_cdrom($drive);
2035
2036 my $volid = $drive->{file};
5e67a2d2
DC
2037 return if !$volid || $volid =~ m|^/|;
2038
2039 die "base volume '$volid' is still in use by linked cloned\n"
2040 if PVE::Storage::volume_is_base_and_used($storecfg, $volid);
2041
2042 });
2043 }
2044
19672434 2045 # only remove disks owned by this VM
1e3baf05
DM
2046 foreach_drive($conf, sub {
2047 my ($ds, $drive) = @_;
9c52f5ed 2048 return if drive_is_cdrom($drive, 1);
1e3baf05
DM
2049
2050 my $volid = $drive->{file};
ff1a2432 2051 return if !$volid || $volid =~ m|^/|;
1e3baf05 2052
6b64503e 2053 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
ff1a2432 2054 return if !$path || !$owner || ($owner != $vmid);
1e3baf05 2055
a2f50f01 2056 eval { PVE::Storage::vdisk_free($storecfg, $volid) };
31b52247 2057 warn "Could not remove disk '$volid', check manually: $@" if $@;
1e3baf05 2058 });
19672434 2059
1e3baf05 2060 # also remove unused disk
a2f50f01
TL
2061 my $vmdisks = PVE::Storage::vdisk_list($storecfg, undef, $vmid);
2062 PVE::Storage::foreach_volid($vmdisks, sub {
2063 my ($volid, $sid, $volname, $d) = @_;
2064 eval { PVE::Storage::vdisk_free($storecfg, $volid) };
1e3baf05 2065 warn $@ if $@;
a2f50f01 2066 });
dfda979e 2067
b04ea584 2068 if (defined $replacement_conf) {
8baf8bc7 2069 PVE::QemuConfig->write_config($vmid, $replacement_conf);
dfda979e
DJ
2070 } else {
2071 PVE::QemuConfig->destroy_config($vmid);
2072 }
1e3baf05
DM
2073}
2074
1e3baf05
DM
2075sub parse_vm_config {
2076 my ($filename, $raw) = @_;
2077
2078 return undef if !defined($raw);
2079
554ac7e7 2080 my $res = {
fc1ddcdc 2081 digest => Digest::SHA::sha1_hex($raw),
0d18dcfc 2082 snapshots => {},
0d732d16 2083 pending => {},
554ac7e7 2084 };
1e3baf05 2085
19672434 2086 $filename =~ m|/qemu-server/(\d+)\.conf$|
1e3baf05
DM
2087 || die "got strange filename '$filename'";
2088
2089 my $vmid = $1;
2090
0d18dcfc 2091 my $conf = $res;
b0ec896e 2092 my $descr;
e297c490 2093 my $section = '';
0581fe4f 2094
0d18dcfc
DM
2095 my @lines = split(/\n/, $raw);
2096 foreach my $line (@lines) {
1e3baf05 2097 next if $line =~ m/^\s*$/;
be190583 2098
eab09f4e 2099 if ($line =~ m/^\[PENDING\]\s*$/i) {
e297c490 2100 $section = 'pending';
b0ec896e
DM
2101 if (defined($descr)) {
2102 $descr =~ s/\s+$//;
2103 $conf->{description} = $descr;
2104 }
2105 $descr = undef;
e297c490 2106 $conf = $res->{$section} = {};
eab09f4e
AD
2107 next;
2108
0d732d16 2109 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
e297c490 2110 $section = $1;
b0ec896e
DM
2111 if (defined($descr)) {
2112 $descr =~ s/\s+$//;
2113 $conf->{description} = $descr;
2114 }
2115 $descr = undef;
e297c490 2116 $conf = $res->{snapshots}->{$section} = {};
0d18dcfc
DM
2117 next;
2118 }
1e3baf05 2119
0581fe4f 2120 if ($line =~ m/^\#(.*)\s*$/) {
b0ec896e 2121 $descr = '' if !defined($descr);
0581fe4f
DM
2122 $descr .= PVE::Tools::decode_text($1) . "\n";
2123 next;
2124 }
2125
1e3baf05 2126 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
b0ec896e 2127 $descr = '' if !defined($descr);
0581fe4f 2128 $descr .= PVE::Tools::decode_text($2);
0d18dcfc
DM
2129 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2130 $conf->{snapstate} = $1;
1e3baf05
DM
2131 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2132 my $key = $1;
2133 my $value = $2;
0d18dcfc 2134 $conf->{$key} = $value;
ef824322 2135 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
e297c490 2136 my $value = $1;
ef824322
DM
2137 if ($section eq 'pending') {
2138 $conf->{delete} = $value; # we parse this later
2139 } else {
2140 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
eab09f4e 2141 }
15cf7698 2142 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
1e3baf05
DM
2143 my $key = $1;
2144 my $value = $2;
2145 eval { $value = check_type($key, $value); };
2146 if ($@) {
2147 warn "vm $vmid - unable to parse value of '$key' - $@";
2148 } else {
b799312f 2149 $key = 'ide2' if $key eq 'cdrom';
1e3baf05 2150 my $fmt = $confdesc->{$key}->{format};
b799312f 2151 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
1e3baf05
DM
2152 my $v = parse_drive($key, $value);
2153 if (my $volid = filename_to_volume_id($vmid, $v->{file}, $v->{media})) {
2154 $v->{file} = $volid;
71c58bb7 2155 $value = print_drive($v);
1e3baf05
DM
2156 } else {
2157 warn "vm $vmid - unable to parse value of '$key'\n";
2158 next;
2159 }
2160 }
2161
b799312f 2162 $conf->{$key} = $value;
1e3baf05
DM
2163 }
2164 }
2165 }
2166
b0ec896e
DM
2167 if (defined($descr)) {
2168 $descr =~ s/\s+$//;
2169 $conf->{description} = $descr;
2170 }
0d18dcfc 2171 delete $res->{snapstate}; # just to be sure
1e3baf05
DM
2172
2173 return $res;
2174}
2175
1858638f
DM
2176sub write_vm_config {
2177 my ($filename, $conf) = @_;
1e3baf05 2178
0d18dcfc
DM
2179 delete $conf->{snapstate}; # just to be sure
2180
1858638f
DM
2181 if ($conf->{cdrom}) {
2182 die "option ide2 conflicts with cdrom\n" if $conf->{ide2};
2183 $conf->{ide2} = $conf->{cdrom};
2184 delete $conf->{cdrom};
2185 }
1e3baf05
DM
2186
2187 # we do not use 'smp' any longer
1858638f
DM
2188 if ($conf->{sockets}) {
2189 delete $conf->{smp};
2190 } elsif ($conf->{smp}) {
2191 $conf->{sockets} = $conf->{smp};
2192 delete $conf->{cores};
2193 delete $conf->{smp};
1e3baf05
DM
2194 }
2195
ee2f90b1 2196 my $used_volids = {};
0d18dcfc 2197
ee2f90b1 2198 my $cleanup_config = sub {
ef824322 2199 my ($cref, $pending, $snapname) = @_;
1858638f 2200
ee2f90b1
DM
2201 foreach my $key (keys %$cref) {
2202 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
ef824322 2203 $key eq 'snapstate' || $key eq 'pending';
ee2f90b1 2204 my $value = $cref->{$key};
ef824322
DM
2205 if ($key eq 'delete') {
2206 die "propertry 'delete' is only allowed in [PENDING]\n"
2207 if !$pending;
2208 # fixme: check syntax?
2209 next;
2210 }
ee2f90b1
DM
2211 eval { $value = check_type($key, $value); };
2212 die "unable to parse value of '$key' - $@" if $@;
1858638f 2213
ee2f90b1
DM
2214 $cref->{$key} = $value;
2215
74479ee9 2216 if (!$snapname && is_valid_drivename($key)) {
ed221350 2217 my $drive = parse_drive($key, $value);
ee2f90b1
DM
2218 $used_volids->{$drive->{file}} = 1 if $drive && $drive->{file};
2219 }
1e3baf05 2220 }
ee2f90b1
DM
2221 };
2222
2223 &$cleanup_config($conf);
ef824322
DM
2224
2225 &$cleanup_config($conf->{pending}, 1);
2226
ee2f90b1 2227 foreach my $snapname (keys %{$conf->{snapshots}}) {
15c6e277 2228 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
ef824322 2229 &$cleanup_config($conf->{snapshots}->{$snapname}, undef, $snapname);
1e3baf05
DM
2230 }
2231
1858638f
DM
2232 # remove 'unusedX' settings if we re-add a volume
2233 foreach my $key (keys %$conf) {
2234 my $value = $conf->{$key};
ee2f90b1 2235 if ($key =~ m/^unused/ && $used_volids->{$value}) {
1858638f 2236 delete $conf->{$key};
1e3baf05 2237 }
1858638f 2238 }
be190583 2239
0d18dcfc 2240 my $generate_raw_config = sub {
b0ec896e 2241 my ($conf, $pending) = @_;
0581fe4f 2242
0d18dcfc
DM
2243 my $raw = '';
2244
2245 # add description as comment to top of file
b0ec896e
DM
2246 if (defined(my $descr = $conf->{description})) {
2247 if ($descr) {
2248 foreach my $cl (split(/\n/, $descr)) {
2249 $raw .= '#' . PVE::Tools::encode_text($cl) . "\n";
2250 }
2251 } else {
2252 $raw .= "#\n" if $pending;
2253 }
0d18dcfc
DM
2254 }
2255
2256 foreach my $key (sort keys %$conf) {
ef824322 2257 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
0d18dcfc
DM
2258 $raw .= "$key: $conf->{$key}\n";
2259 }
2260 return $raw;
2261 };
0581fe4f 2262
0d18dcfc 2263 my $raw = &$generate_raw_config($conf);
ef824322
DM
2264
2265 if (scalar(keys %{$conf->{pending}})){
2266 $raw .= "\n[PENDING]\n";
b0ec896e 2267 $raw .= &$generate_raw_config($conf->{pending}, 1);
ef824322
DM
2268 }
2269
0d18dcfc
DM
2270 foreach my $snapname (sort keys %{$conf->{snapshots}}) {
2271 $raw .= "\n[$snapname]\n";
2272 $raw .= &$generate_raw_config($conf->{snapshots}->{$snapname});
1858638f 2273 }
1e3baf05 2274
1858638f
DM
2275 return $raw;
2276}
1e3baf05 2277
19672434 2278sub load_defaults {
1e3baf05
DM
2279
2280 my $res = {};
2281
2282 # we use static defaults from our JSON schema configuration
2283 foreach my $key (keys %$confdesc) {
2284 if (defined(my $default = $confdesc->{$key}->{default})) {
2285 $res->{$key} = $default;
2286 }
2287 }
19672434 2288
1e3baf05
DM
2289 return $res;
2290}
2291
2292sub config_list {
2293 my $vmlist = PVE::Cluster::get_vmlist();
2294 my $res = {};
2295 return $res if !$vmlist || !$vmlist->{ids};
2296 my $ids = $vmlist->{ids};
38277afc 2297 my $nodename = nodename();
1e3baf05 2298
1e3baf05
DM
2299 foreach my $vmid (keys %$ids) {
2300 my $d = $ids->{$vmid};
2301 next if !$d->{node} || $d->{node} ne $nodename;
5ee957cc 2302 next if !$d->{type} || $d->{type} ne 'qemu';
1e3baf05
DM
2303 $res->{$vmid}->{exists} = 1;
2304 }
2305 return $res;
2306}
2307
64e13401
DM
2308# test if VM uses local resources (to prevent migration)
2309sub check_local_resources {
2310 my ($conf, $noerr) = @_;
2311
ca6abacf 2312 my @loc_res = ();
19672434 2313
ca6abacf
TM
2314 push @loc_res, "hostusb" if $conf->{hostusb}; # old syntax
2315 push @loc_res, "hostpci" if $conf->{hostpci}; # old syntax
64e13401 2316
ca6abacf 2317 push @loc_res, "ivshmem" if $conf->{ivshmem};
6dbcb073 2318
0d29ab3b 2319 foreach my $k (keys %$conf) {
a9ce7583 2320 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
d44712fc
EK
2321 # sockets are safe: they will recreated be on the target side post-migrate
2322 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
ca6abacf 2323 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
64e13401
DM
2324 }
2325
ca6abacf 2326 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
64e13401 2327
ca6abacf 2328 return \@loc_res;
64e13401
DM
2329}
2330
719893a9 2331# check if used storages are available on all nodes (use by migrate)
47152e2e
DM
2332sub check_storage_availability {
2333 my ($storecfg, $conf, $node) = @_;
2334
2335 foreach_drive($conf, sub {
2336 my ($ds, $drive) = @_;
2337
2338 my $volid = $drive->{file};
2339 return if !$volid;
2340
2341 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2342 return if !$sid;
2343
2344 # check if storage is available on both nodes
2345 my $scfg = PVE::Storage::storage_check_node($storecfg, $sid);
2346 PVE::Storage::storage_check_node($storecfg, $sid, $node);
2347 });
2348}
2349
719893a9
DM
2350# list nodes where all VM images are available (used by has_feature API)
2351sub shared_nodes {
2352 my ($conf, $storecfg) = @_;
2353
2354 my $nodelist = PVE::Cluster::get_nodelist();
2355 my $nodehash = { map { $_ => 1 } @$nodelist };
38277afc 2356 my $nodename = nodename();
be190583 2357
719893a9
DM
2358 foreach_drive($conf, sub {
2359 my ($ds, $drive) = @_;
2360
2361 my $volid = $drive->{file};
2362 return if !$volid;
2363
2364 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2365 if ($storeid) {
2366 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2367 if ($scfg->{disable}) {
2368 $nodehash = {};
2369 } elsif (my $avail = $scfg->{nodes}) {
2370 foreach my $node (keys %$nodehash) {
2371 delete $nodehash->{$node} if !$avail->{$node};
2372 }
2373 } elsif (!$scfg->{shared}) {
2374 foreach my $node (keys %$nodehash) {
2375 delete $nodehash->{$node} if $node ne $nodename
2376 }
2377 }
2378 }
2379 });
2380
2381 return $nodehash
2382}
2383
f25852c2
TM
2384sub check_local_storage_availability {
2385 my ($conf, $storecfg) = @_;
2386
2387 my $nodelist = PVE::Cluster::get_nodelist();
2388 my $nodehash = { map { $_ => {} } @$nodelist };
2389
2390 foreach_drive($conf, sub {
2391 my ($ds, $drive) = @_;
2392
2393 my $volid = $drive->{file};
2394 return if !$volid;
2395
2396 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2397 if ($storeid) {
2398 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2399
2400 if ($scfg->{disable}) {
2401 foreach my $node (keys %$nodehash) {
32075a2c 2402 $nodehash->{$node}->{unavailable_storages}->{$storeid} = 1;
f25852c2
TM
2403 }
2404 } elsif (my $avail = $scfg->{nodes}) {
2405 foreach my $node (keys %$nodehash) {
2406 if (!$avail->{$node}) {
32075a2c 2407 $nodehash->{$node}->{unavailable_storages}->{$storeid} = 1;
f25852c2
TM
2408 }
2409 }
2410 }
2411 }
2412 });
2413
32075a2c
TL
2414 foreach my $node (values %$nodehash) {
2415 if (my $unavail = $node->{unavailable_storages}) {
2416 $node->{unavailable_storages} = [ sort keys %$unavail ];
2417 }
2418 }
2419
f25852c2
TM
2420 return $nodehash
2421}
2422
babf613a 2423# Compat only, use assert_config_exists_on_node and vm_running_locally where possible
1e3baf05 2424sub check_running {
7e8dcf2c 2425 my ($vmid, $nocheck, $node) = @_;
1e3baf05 2426
babf613a
SR
2427 PVE::QemuConfig::assert_config_exists_on_node($vmid, $node) if !$nocheck;
2428 return PVE::QemuServer::Helpers::vm_running_locally($vmid);
1e3baf05
DM
2429}
2430
2431sub vzlist {
19672434 2432
1e3baf05
DM
2433 my $vzlist = config_list();
2434
d036e418 2435 my $fd = IO::Dir->new($PVE::QemuServer::Helpers::var_run_tmpdir) || return $vzlist;
1e3baf05 2436
19672434 2437 while (defined(my $de = $fd->read)) {
1e3baf05
DM
2438 next if $de !~ m/^(\d+)\.pid$/;
2439 my $vmid = $1;
6b64503e
DM
2440 next if !defined($vzlist->{$vmid});
2441 if (my $pid = check_running($vmid)) {
1e3baf05
DM
2442 $vzlist->{$vmid}->{pid} = $pid;
2443 }
2444 }
2445
2446 return $vzlist;
2447}
2448
b1a70cab
DM
2449our $vmstatus_return_properties = {
2450 vmid => get_standard_option('pve-vmid'),
2451 status => {
2452 description => "Qemu process status.",
2453 type => 'string',
2454 enum => ['stopped', 'running'],
2455 },
2456 maxmem => {
2457 description => "Maximum memory in bytes.",
2458 type => 'integer',
2459 optional => 1,
2460 renderer => 'bytes',
2461 },
2462 maxdisk => {
2463 description => "Root disk size in bytes.",
2464 type => 'integer',
2465 optional => 1,
2466 renderer => 'bytes',
2467 },
2468 name => {
2469 description => "VM name.",
2470 type => 'string',
2471 optional => 1,
2472 },
2473 qmpstatus => {
2474 description => "Qemu QMP agent status.",
2475 type => 'string',
2476 optional => 1,
2477 },
2478 pid => {
2479 description => "PID of running qemu process.",
2480 type => 'integer',
2481 optional => 1,
2482 },
2483 uptime => {
2484 description => "Uptime.",
2485 type => 'integer',
2486 optional => 1,
2487 renderer => 'duration',
2488 },
2489 cpus => {
2490 description => "Maximum usable CPUs.",
2491 type => 'number',
2492 optional => 1,
2493 },
e6ed61b4 2494 lock => {
11efdfa5 2495 description => "The current config lock, if any.",
e6ed61b4
DC
2496 type => 'string',
2497 optional => 1,
b8e7068a
DC
2498 },
2499 tags => {
2500 description => "The current configured tags, if any",
2501 type => 'string',
2502 optional => 1,
2503 },
b1a70cab
DM
2504};
2505
1e3baf05
DM
2506my $last_proc_pid_stat;
2507
03a33f30
DM
2508# get VM status information
2509# This must be fast and should not block ($full == false)
2510# We only query KVM using QMP if $full == true (this can be slow)
1e3baf05 2511sub vmstatus {
03a33f30 2512 my ($opt_vmid, $full) = @_;
1e3baf05
DM
2513
2514 my $res = {};
2515
19672434 2516 my $storecfg = PVE::Storage::config();
1e3baf05
DM
2517
2518 my $list = vzlist();
3618ee99
EK
2519 my $defaults = load_defaults();
2520
694fcad4 2521 my ($uptime) = PVE::ProcFSTools::read_proc_uptime(1);
1e3baf05 2522
ae4915a2
DM
2523 my $cpucount = $cpuinfo->{cpus} || 1;
2524
1e3baf05
DM
2525 foreach my $vmid (keys %$list) {
2526 next if $opt_vmid && ($vmid ne $opt_vmid);
2527
9f78b695 2528 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 2529
b1a70cab 2530 my $d = { vmid => $vmid };
1e3baf05
DM
2531 $d->{pid} = $list->{$vmid}->{pid};
2532
2533 # fixme: better status?
2534 $d->{status} = $list->{$vmid}->{pid} ? 'running' : 'stopped';
2535
776c5f50 2536 my $size = PVE::QemuServer::Drive::bootdisk_size($storecfg, $conf);
af990afe
DM
2537 if (defined($size)) {
2538 $d->{disk} = 0; # no info available
1e3baf05
DM
2539 $d->{maxdisk} = $size;
2540 } else {
2541 $d->{disk} = 0;
2542 $d->{maxdisk} = 0;
2543 }
2544
3618ee99
EK
2545 $d->{cpus} = ($conf->{sockets} || $defaults->{sockets})
2546 * ($conf->{cores} || $defaults->{cores});
ae4915a2 2547 $d->{cpus} = $cpucount if $d->{cpus} > $cpucount;
d7c8364b 2548 $d->{cpus} = $conf->{vcpus} if $conf->{vcpus};
ae4915a2 2549
1e3baf05 2550 $d->{name} = $conf->{name} || "VM $vmid";
3618ee99
EK
2551 $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024)
2552 : $defaults->{memory}*(1024*1024);
1e3baf05 2553
8b1accf7 2554 if ($conf->{balloon}) {
4bdb0514 2555 $d->{balloon_min} = $conf->{balloon}*(1024*1024);
3618ee99
EK
2556 $d->{shares} = defined($conf->{shares}) ? $conf->{shares}
2557 : $defaults->{shares};
8b1accf7
DM
2558 }
2559
1e3baf05
DM
2560 $d->{uptime} = 0;
2561 $d->{cpu} = 0;
1e3baf05
DM
2562 $d->{mem} = 0;
2563
2564 $d->{netout} = 0;
2565 $d->{netin} = 0;
2566
2567 $d->{diskread} = 0;
2568 $d->{diskwrite} = 0;
2569
ffda963f 2570 $d->{template} = PVE::QemuConfig->is_template($conf);
4d8c851b 2571
8107b378 2572 $d->{serial} = 1 if conf_has_serial($conf);
e6ed61b4 2573 $d->{lock} = $conf->{lock} if $conf->{lock};
b8e7068a 2574 $d->{tags} = $conf->{tags} if defined($conf->{tags});
8107b378 2575
1e3baf05
DM
2576 $res->{$vmid} = $d;
2577 }
2578
2579 my $netdev = PVE::ProcFSTools::read_proc_net_dev();
2580 foreach my $dev (keys %$netdev) {
2581 next if $dev !~ m/^tap([1-9]\d*)i/;
2582 my $vmid = $1;
2583 my $d = $res->{$vmid};
2584 next if !$d;
19672434 2585
1e3baf05
DM
2586 $d->{netout} += $netdev->{$dev}->{receive};
2587 $d->{netin} += $netdev->{$dev}->{transmit};
604ea644
AD
2588
2589 if ($full) {
2590 $d->{nics}->{$dev}->{netout} = $netdev->{$dev}->{receive};
2591 $d->{nics}->{$dev}->{netin} = $netdev->{$dev}->{transmit};
2592 }
2593
1e3baf05
DM
2594 }
2595
1e3baf05
DM
2596 my $ctime = gettimeofday;
2597
2598 foreach my $vmid (keys %$list) {
2599
2600 my $d = $res->{$vmid};
2601 my $pid = $d->{pid};
2602 next if !$pid;
2603
694fcad4
DM
2604 my $pstat = PVE::ProcFSTools::read_proc_pid_stat($pid);
2605 next if !$pstat; # not running
19672434 2606
694fcad4 2607 my $used = $pstat->{utime} + $pstat->{stime};
1e3baf05 2608
694fcad4 2609 $d->{uptime} = int(($uptime - $pstat->{starttime})/$cpuinfo->{user_hz});
1e3baf05 2610
694fcad4 2611 if ($pstat->{vsize}) {
6b64503e 2612 $d->{mem} = int(($pstat->{rss}/$pstat->{vsize})*$d->{maxmem});
1e3baf05
DM
2613 }
2614
2615 my $old = $last_proc_pid_stat->{$pid};
2616 if (!$old) {
19672434
DM
2617 $last_proc_pid_stat->{$pid} = {
2618 time => $ctime,
1e3baf05
DM
2619 used => $used,
2620 cpu => 0,
1e3baf05
DM
2621 };
2622 next;
2623 }
2624
7f0b5beb 2625 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz};
1e3baf05
DM
2626
2627 if ($dtime > 1000) {
2628 my $dutime = $used - $old->{used};
2629
ae4915a2 2630 $d->{cpu} = (($dutime/$dtime)* $cpucount) / $d->{cpus};
1e3baf05 2631 $last_proc_pid_stat->{$pid} = {
19672434 2632 time => $ctime,
1e3baf05
DM
2633 used => $used,
2634 cpu => $d->{cpu},
1e3baf05
DM
2635 };
2636 } else {
2637 $d->{cpu} = $old->{cpu};
1e3baf05
DM
2638 }
2639 }
2640
f5eb281a 2641 return $res if !$full;
03a33f30
DM
2642
2643 my $qmpclient = PVE::QMPClient->new();
2644
64e7fcf2
DM
2645 my $ballooncb = sub {
2646 my ($vmid, $resp) = @_;
2647
2648 my $info = $resp->{'return'};
38babf81
DM
2649 return if !$info->{max_mem};
2650
64e7fcf2
DM
2651 my $d = $res->{$vmid};
2652
38babf81
DM
2653 # use memory assigned to VM
2654 $d->{maxmem} = $info->{max_mem};
2655 $d->{balloon} = $info->{actual};
2656
2657 if (defined($info->{total_mem}) && defined($info->{free_mem})) {
2658 $d->{mem} = $info->{total_mem} - $info->{free_mem};
2659 $d->{freemem} = $info->{free_mem};
64e7fcf2
DM
2660 }
2661
604ea644 2662 $d->{ballooninfo} = $info;
64e7fcf2
DM
2663 };
2664
03a33f30
DM
2665 my $blockstatscb = sub {
2666 my ($vmid, $resp) = @_;
2667 my $data = $resp->{'return'} || [];
2668 my $totalrdbytes = 0;
2669 my $totalwrbytes = 0;
604ea644 2670
03a33f30
DM
2671 for my $blockstat (@$data) {
2672 $totalrdbytes = $totalrdbytes + $blockstat->{stats}->{rd_bytes};
2673 $totalwrbytes = $totalwrbytes + $blockstat->{stats}->{wr_bytes};
604ea644
AD
2674
2675 $blockstat->{device} =~ s/drive-//;
2676 $res->{$vmid}->{blockstat}->{$blockstat->{device}} = $blockstat->{stats};
03a33f30
DM
2677 }
2678 $res->{$vmid}->{diskread} = $totalrdbytes;
2679 $res->{$vmid}->{diskwrite} = $totalwrbytes;
2680 };
2681
2682 my $statuscb = sub {
2683 my ($vmid, $resp) = @_;
64e7fcf2 2684
03a33f30 2685 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
64e7fcf2
DM
2686 # this fails if ballon driver is not loaded, so this must be
2687 # the last commnand (following command are aborted if this fails).
38babf81 2688 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
03a33f30
DM
2689
2690 my $status = 'unknown';
2691 if (!defined($status = $resp->{'return'}->{status})) {
2692 warn "unable to get VM status\n";
2693 return;
2694 }
2695
2696 $res->{$vmid}->{qmpstatus} = $resp->{'return'}->{status};
2697 };
2698
2699 foreach my $vmid (keys %$list) {
2700 next if $opt_vmid && ($vmid ne $opt_vmid);
2701 next if !$res->{$vmid}->{pid}; # not running
2702 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2703 }
2704
b017fbda 2705 $qmpclient->queue_execute(undef, 2);
03a33f30
DM
2706
2707 foreach my $vmid (keys %$list) {
2708 next if $opt_vmid && ($vmid ne $opt_vmid);
2709 $res->{$vmid}->{qmpstatus} = $res->{$vmid}->{status} if !$res->{$vmid}->{qmpstatus};
2710 }
2711
1e3baf05
DM
2712 return $res;
2713}
2714
8107b378
DC
2715sub conf_has_serial {
2716 my ($conf) = @_;
2717
2718 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2719 if ($conf->{"serial$i"}) {
2720 return 1;
2721 }
2722 }
2723
2724 return 0;
2725}
2726
d5535a00
TL
2727sub conf_has_audio {
2728 my ($conf, $id) = @_;
2729
2730 $id //= 0;
2731 my $audio = $conf->{"audio$id"};
2732 return undef if !defined($audio);
2733
2734 my $audioproperties = PVE::JSONSchema::parse_property_string($audio_fmt, $audio);
2735 my $audiodriver = $audioproperties->{driver} // 'spice';
2736
2737 return {
2738 dev => $audioproperties->{device},
b0f96836 2739 dev_id => "audiodev$id",
d5535a00
TL
2740 backend => $audiodriver,
2741 backend_id => "$audiodriver-backend${id}",
2742 };
2743}
2744
86b8228b
DM
2745sub vga_conf_has_spice {
2746 my ($vga) = @_;
2747
55655ebc
DC
2748 my $vgaconf = parse_vga($vga);
2749 my $vgatype = $vgaconf->{type};
2750 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
590e698c
DM
2751
2752 return $1 || 1;
86b8228b
DM
2753}
2754
d731ecbe
WB
2755sub is_native($) {
2756 my ($arch) = @_;
2757 return get_host_arch() eq $arch;
2758}
2759
045749f2
TL
2760sub get_vm_arch {
2761 my ($conf) = @_;
2762 return $conf->{arch} // get_host_arch();
2763}
2764
d731ecbe
WB
2765my $default_machines = {
2766 x86_64 => 'pc',
2767 aarch64 => 'virt',
2768};
2769
045749f2 2770sub get_vm_machine {
ac0077cc 2771 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
045749f2
TL
2772
2773 my $machine = $forcemachine || $conf->{machine};
d731ecbe 2774
9471e48b 2775 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
045749f2
TL
2776 $arch //= 'x86_64';
2777 $machine ||= $default_machines->{$arch};
ac0077cc
SR
2778 if ($add_pve_version) {
2779 $kvmversion //= kvm_user_version();
2780 my $pvever = PVE::QemuServer::Machine::get_pve_version($kvmversion);
2781 $machine .= "+pve$pvever";
2782 }
2783 }
2784
2785 if ($add_pve_version && $machine !~ m/\+pve\d+$/) {
2786 # for version-pinned machines that do not include a pve-version (e.g.
2787 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
2788 $machine .= '+pve0';
045749f2
TL
2789 }
2790
2791 return $machine;
d731ecbe
WB
2792}
2793
96ed3574
WB
2794sub get_ovmf_files($) {
2795 my ($arch) = @_;
2796
2797 my $ovmf = $OVMF->{$arch}
2798 or die "no OVMF images known for architecture '$arch'\n";
2799
2800 return @$ovmf;
2801}
2802
6908fd9b
WB
2803my $Arch2Qemu = {
2804 aarch64 => '/usr/bin/qemu-system-aarch64',
2805 x86_64 => '/usr/bin/qemu-system-x86_64',
2806};
2807sub get_command_for_arch($) {
2808 my ($arch) = @_;
2809 return '/usr/bin/kvm' if is_native($arch);
2810
2811 my $cmd = $Arch2Qemu->{$arch}
2812 or die "don't know how to emulate architecture '$arch'\n";
2813 return $cmd;
2814}
2815
05a4c550
SR
2816# To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
2817# to use in a QEMU command line (-cpu element), first array_intersect the result
2818# of query_supported_ with query_understood_. This is necessary because:
2819#
2820# a) query_understood_ returns flags the host cannot use and
2821# b) query_supported_ (rather the QMP call) doesn't actually return CPU
2822# flags, but CPU settings - with most of them being flags. Those settings
2823# (and some flags, curiously) cannot be specified as a "-cpu" argument.
2824#
2825# query_supported_ needs to start up to 2 temporary VMs and is therefore rather
2826# expensive. If you need the value returned from this, you can get it much
2827# cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
2828# $accel being 'kvm' or 'tcg'.
2829#
2830# pvestatd calls this function on startup and whenever the QEMU/KVM version
2831# changes, automatically populating pmxcfs.
2832#
2833# Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
2834# since kvm and tcg machines support different flags
2835#
2836sub query_supported_cpu_flags {
52cffab6 2837 my ($arch) = @_;
05a4c550 2838
52cffab6
SR
2839 $arch //= get_host_arch();
2840 my $default_machine = $default_machines->{$arch};
2841
2842 my $flags = {};
05a4c550
SR
2843
2844 # FIXME: Once this is merged, the code below should work for ARM as well:
2845 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
2846 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
2847 $arch eq "aarch64";
2848
2849 my $kvm_supported = defined(kvm_version());
2850 my $qemu_cmd = get_command_for_arch($arch);
2851 my $fakevmid = -1;
2852 my $pidfile = PVE::QemuServer::Helpers::pidfile_name($fakevmid);
2853
2854 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
2855 my $query_supported_run_qemu = sub {
2856 my ($kvm) = @_;
2857
2858 my $flags = {};
2859 my $cmd = [
2860 $qemu_cmd,
2861 '-machine', $default_machine,
2862 '-display', 'none',
2863 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server,nowait",
2864 '-mon', 'chardev=qmp,mode=control',
2865 '-pidfile', $pidfile,
2866 '-S', '-daemonize'
2867 ];
2868
2869 if (!$kvm) {
2870 push @$cmd, '-accel', 'tcg';
2871 }
2872
2873 my $rc = run_command($cmd, noerr => 1, quiet => 0);
2874 die "QEMU flag querying VM exited with code " . $rc if $rc;
2875
2876 eval {
2877 my $cmd_result = mon_cmd(
2878 $fakevmid,
2879 'query-cpu-model-expansion',
2880 type => 'full',
2881 model => { name => 'host' }
2882 );
2883
2884 my $props = $cmd_result->{model}->{props};
2885 foreach my $prop (keys %$props) {
2886 next if $props->{$prop} ne '1';
2887 # QEMU returns some flags multiple times, with '_', '.' or '-'
2888 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
2889 # We only keep those with underscores, to match /proc/cpuinfo
2890 $prop =~ s/\.|-/_/g;
2891 $flags->{$prop} = 1;
2892 }
2893 };
2894 my $err = $@;
2895
2896 # force stop with 10 sec timeout and 'nocheck'
2897 # always stop, even if QMP failed
2898 vm_stop(undef, $fakevmid, 1, 1, 10, 0, 1);
2899
2900 die $err if $err;
2901
2902 return [ sort keys %$flags ];
2903 };
2904
2905 # We need to query QEMU twice, since KVM and TCG have different supported flags
2906 PVE::QemuConfig->lock_config($fakevmid, sub {
2907 $flags->{tcg} = eval { $query_supported_run_qemu->(0) };
2908 warn "warning: failed querying supported tcg flags: $@\n" if $@;
2909
2910 if ($kvm_supported) {
2911 $flags->{kvm} = eval { $query_supported_run_qemu->(1) };
2912 warn "warning: failed querying supported kvm flags: $@\n" if $@;
2913 }
2914 });
2915
2916 return $flags;
2917}
2918
2919# Understood CPU flags are written to a file at 'pve-qemu' compile time
2920my $understood_cpu_flag_dir = "/usr/share/kvm";
2921sub query_understood_cpu_flags {
2922 my $arch = get_host_arch();
2923 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
2924
2925 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
2926 if ! -e $filepath;
2927
2928 my $raw = file_get_contents($filepath);
2929 $raw =~ s/^\s+|\s+$//g;
2930 my @flags = split(/\s+/, $raw);
2931
2932 return \@flags;
2933}
2934
1e3baf05 2935sub config_to_command {
67812f9c 2936 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
1e3baf05
DM
2937
2938 my $cmd = [];
8c559505
DM
2939 my $globalFlags = [];
2940 my $machineFlags = [];
2941 my $rtcFlags = [];
5bdcf937 2942 my $devices = [];
b78ebef7 2943 my $pciaddr = '';
5bdcf937 2944 my $bridges = {};
b42d3cf9 2945 my $ostype = $conf->{ostype};
4317f69f 2946 my $winversion = windows_version($ostype);
d731ecbe 2947 my $kvm = $conf->{kvm};
38277afc 2948 my $nodename = nodename();
d731ecbe 2949
045749f2 2950 my $arch = get_vm_arch($conf);
1476b99f
DC
2951 my $kvm_binary = get_command_for_arch($arch);
2952 my $kvmver = kvm_user_version($kvm_binary);
045749f2 2953
a04dd5c4
SR
2954 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
2955 $kvmver //= "undefined";
2956 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
2957 }
2958
9471e48b
TL
2959 my $add_pve_version = min_version($kvmver, 4, 1);
2960
2961 my $machine_type = get_vm_machine($conf, $forcemachine, $arch, $add_pve_version);
2962 my $machine_version = PVE::QemuServer::Machine::extract_version($machine_type, $kvmver);
d731ecbe 2963 $kvm //= 1 if is_native($arch);
4317f69f 2964
a77a53ae 2965 $machine_version =~ m/(\d+)\.(\d+)/;
ac0077cc 2966 my ($machine_major, $machine_minor) = ($1, $2);
cbb39a7e 2967 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type', please upgrade node '$nodename'\n"
ac0077cc
SR
2968 if !PVE::QemuServer::min_version($kvmver, $machine_major, $machine_minor);
2969
2970 if (!PVE::QemuServer::Machine::can_run_pve_machine_version($machine_version, $kvmver)) {
2971 my $max_pve_version = PVE::QemuServer::Machine::get_pve_version($machine_version);
2972 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is pve$max_pve_version)"
2973 . " is too old to run machine type '$machine_type', please upgrade node '$nodename'\n";
2974 }
2975
2976 # if a specific +pve version is required for a feature, use $version_guard
2977 # instead of min_version to allow machines to be run with the minimum
2978 # required version
2979 my $required_pve_version = 0;
2980 my $version_guard = sub {
2981 my ($major, $minor, $pve) = @_;
2982 return 0 if !min_version($machine_version, $major, $minor, $pve);
47f35977
SR
2983 my $max_pve = PVE::QemuServer::Machine::get_pve_version("$major.$minor");
2984 return 1 if min_version($machine_version, $major, $minor, $max_pve+1);
ac0077cc
SR
2985 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
2986 return 1;
2987 };
a77a53ae 2988
d731ecbe
WB
2989 if ($kvm) {
2990 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
2991 if !defined kvm_version();
2992 }
bfcd9b7e 2993
3392d6ca 2994 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
4d3f29ed 2995 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
249c4a6c
AD
2996 my $use_old_bios_files = undef;
2997 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
db656e5f 2998
f08e17c7
AD
2999 my $cpuunits = defined($conf->{cpuunits}) ?
3000 $conf->{cpuunits} : $defaults->{cpuunits};
3001
1476b99f 3002 push @$cmd, $kvm_binary;
1e3baf05
DM
3003
3004 push @$cmd, '-id', $vmid;
3005
e4d4cda1
HR
3006 my $vmname = $conf->{name} || "vm$vmid";
3007
3008 push @$cmd, '-name', $vmname;
3009
1e3baf05
DM
3010 my $use_virtio = 0;
3011
d036e418 3012 my $qmpsocket = PVE::QemuServer::Helpers::qmp_socket($vmid);
c971c4f2
AD
3013 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3014 push @$cmd, '-mon', "chardev=qmp,mode=control";
3015
2ea5fb7e 3016 if (min_version($machine_version, 2, 12)) {
b4496b9e 3017 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
71bd73b5
DC
3018 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3019 }
1e3baf05 3020
d036e418 3021 push @$cmd, '-pidfile' , PVE::QemuServer::Helpers::pidfile_name($vmid);
19672434 3022
1e3baf05
DM
3023 push @$cmd, '-daemonize';
3024
2796e7d5 3025 if ($conf->{smbios1}) {
1f30ac3a
CE
3026 my $smbios_conf = parse_smbios1($conf->{smbios1});
3027 if ($smbios_conf->{base64}) {
3028 # Do not pass base64 flag to qemu
3029 delete $smbios_conf->{base64};
3030 my $smbios_string = "";
3031 foreach my $key (keys %$smbios_conf) {
3032 my $value;
3033 if ($key eq "uuid") {
3034 $value = $smbios_conf->{uuid}
3035 } else {
3036 $value = decode_base64($smbios_conf->{$key});
3037 }
3038 # qemu accepts any binary data, only commas need escaping by double comma
3039 $value =~ s/,/,,/g;
3040 $smbios_string .= "," . $key . "=" . $value if $value;
3041 }
3042 push @$cmd, '-smbios', "type=1" . $smbios_string;
3043 } else {
3044 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3045 }
2796e7d5
DM
3046 }
3047
96ed3574 3048 my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch);
3edb45e7 3049 if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
96ed3574 3050 die "uefi base image not found\n" if ! -f $ovmf_code;
2ddc0a5c 3051
4dcce9ee 3052 my $path;
13bca7b4 3053 my $format;
4dcce9ee 3054 if (my $efidisk = $conf->{efidisk0}) {
ad396d54 3055 my $d = parse_drive('efidisk0', $efidisk);
2ddc0a5c 3056 my ($storeid, $volname) = PVE::Storage::parse_volume_id($d->{file}, 1);
13bca7b4 3057 $format = $d->{format};
2ddc0a5c
DC
3058 if ($storeid) {
3059 $path = PVE::Storage::path($storecfg, $d->{file});
13bca7b4
WB
3060 if (!defined($format)) {
3061 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
3062 $format = qemu_img_format($scfg, $volname);
3063 }
2ddc0a5c
DC
3064 } else {
3065 $path = $d->{file};
13bca7b4
WB
3066 die "efidisk format must be specified\n"
3067 if !defined($format);
2ddc0a5c 3068 }
2ddc0a5c 3069 } else {
4dcce9ee
TL
3070 warn "no efidisk configured! Using temporary efivars disk.\n";
3071 $path = "/tmp/$vmid-ovmf.fd";
96ed3574 3072 PVE::Tools::file_copy($ovmf_vars, $path, -s $ovmf_vars);
13bca7b4 3073 $format = 'raw';
2ddc0a5c 3074 }
4dcce9ee 3075
818ce80e
DC
3076 my $size_str = "";
3077
3078 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3079 $size_str = ",size=" . (-s $ovmf_vars);
3080 }
3081
96ed3574 3082 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
818ce80e 3083 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0$size_str,file=$path";
a783c78e
AD
3084 }
3085
7583d156
DC
3086 # load q35 config
3087 if ($q35) {
3088 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
2ea5fb7e 3089 if (min_version($machine_version, 4, 0)) {
7583d156
DC
3090 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3091 } else {
3092 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3093 }
3094 }
da8b4189 3095
844d8fa6
DC
3096 if ($conf->{vmgenid}) {
3097 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid};
3098 }
3099
d40e5e18 3100 # add usb controllers
d559309f 3101 my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers($conf, $bridges, $arch, $machine_type, $usbdesc->{format}, $MAX_USB_DEVICES);
d40e5e18 3102 push @$devices, @usbcontrollers if @usbcontrollers;
55655ebc 3103 my $vga = parse_vga($conf->{vga});
2fa3151e 3104
55655ebc
DC
3105 my $qxlnum = vga_conf_has_spice($conf->{vga});
3106 $vga->{type} = 'qxl' if $qxlnum;
2fa3151e 3107
55655ebc 3108 if (!$vga->{type}) {
869ad4a7
WB
3109 if ($arch eq 'aarch64') {
3110 $vga->{type} = 'virtio';
2ea5fb7e 3111 } elsif (min_version($machine_version, 2, 9)) {
55655ebc 3112 $vga->{type} = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus';
a2a5cd64 3113 } else {
55655ebc 3114 $vga->{type} = ($winversion >= 6) ? 'std' : 'cirrus';
a2a5cd64 3115 }
5acbfe9e
DM
3116 }
3117
1e3baf05 3118 # enable absolute mouse coordinates (needed by vnc)
5acbfe9e
DM
3119 my $tablet;
3120 if (defined($conf->{tablet})) {
3121 $tablet = $conf->{tablet};
3122 } else {
3123 $tablet = $defaults->{tablet};
590e698c 3124 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
55655ebc 3125 $tablet = 0 if $vga->{type} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
5acbfe9e
DM
3126 }
3127
d559309f
WB
3128 if ($tablet) {
3129 push @$devices, '-device', print_tabletdevice_full($conf, $arch) if $tablet;
3130 my $kbd = print_keyboarddevice_full($conf, $arch);
3131 push @$devices, '-device', $kbd if defined($kbd);
3132 }
b467f79a 3133
16a91d65 3134 my $kvm_off = 0;
4317f69f
AD
3135 my $gpu_passthrough;
3136
1e3baf05 3137 # host pci devices
040b06b7 3138 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
dae0c8e5
TL
3139 my $id = "hostpci$i";
3140 my $d = parse_hostpci($conf->{$id});
2e3b7e2a
AD
3141 next if !$d;
3142
dae0c8e5 3143 if (my $pcie = $d->{pcie}) {
2e3b7e2a 3144 die "q35 machine model is not enabled" if !$q35;
739ba340
DC
3145 # win7 wants to have the pcie devices directly on the pcie bus
3146 # instead of in the root port
3147 if ($winversion == 7) {
dae0c8e5 3148 $pciaddr = print_pcie_addr("${id}bus0");
739ba340 3149 } else {
c4e16381 3150 # add more root ports if needed, 4 are present by default
dae0c8e5 3151 # by pve-q35 cfgs, rest added here on demand.
c4e16381
AL
3152 if ($i > 3) {
3153 push @$devices, '-device', print_pcie_root_port($i);
3154 }
dae0c8e5 3155 $pciaddr = print_pcie_addr($id);
739ba340 3156 }
bd772c2e 3157 } else {
dae0c8e5 3158 $pciaddr = print_pci_addr($id, $bridges, $arch, $machine_type);
2e3b7e2a
AD
3159 }
3160
1f4f447b
WB
3161 my $xvga = '';
3162 if ($d->{'x-vga'}) {
dae0c8e5 3163 $xvga = ',x-vga=on' if !($conf->{bios} && $conf->{bios} eq 'ovmf');
16a91d65 3164 $kvm_off = 1;
bfc0bb81 3165 $vga->{type} = 'none' if !defined($conf->{vga});
4317f69f 3166 $gpu_passthrough = 1;
137483c0 3167 }
dae0c8e5 3168
4543ecf0
AD
3169 my $pcidevices = $d->{pciid};
3170 my $multifunction = 1 if @$pcidevices > 1;
dae0c8e5 3171
6ab45bd7
DC
3172 my $sysfspath;
3173 if ($d->{mdev} && scalar(@$pcidevices) == 1) {
dae0c8e5 3174 my $pci_id = $pcidevices->[0]->{id};
6ab45bd7 3175 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
70740c1a 3176 $sysfspath = "/sys/bus/pci/devices/$pci_id/$uuid";
6ab45bd7 3177 } elsif ($d->{mdev}) {
dae0c8e5 3178 warn "ignoring mediated device '$id' with multifunction device\n";
6ab45bd7 3179 }
2e3b7e2a 3180
4543ecf0 3181 my $j=0;
dae0c8e5 3182 foreach my $pcidevice (@$pcidevices) {
6ab45bd7 3183 my $devicestr = "vfio-pci";
dae0c8e5 3184
6ab45bd7
DC
3185 if ($sysfspath) {
3186 $devicestr .= ",sysfsdev=$sysfspath";
3187 } else {
2fd24788 3188 $devicestr .= ",host=$pcidevice->{id}";
6ab45bd7 3189 }
4543ecf0 3190
dae0c8e5
TL
3191 my $mf_addr = $multifunction ? ".$j" : '';
3192 $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}";
3193
3194 if ($j == 0) {
3195 $devicestr .= ',rombar=0' if defined($d->{rombar}) && !$d->{rombar};
3196 $devicestr .= "$xvga";
4543ecf0 3197 $devicestr .= ",multifunction=on" if $multifunction;
dae0c8e5 3198 $devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile};
4543ecf0
AD
3199 }
3200
3201 push @$devices, '-device', $devicestr;
3202 $j++;
3203 }
1e3baf05
DM
3204 }
3205
3206 # usb devices
ae36393d 3207 my $usb_dev_features = {};
2ea5fb7e 3208 $usb_dev_features->{spice_usb3} = 1 if min_version($machine_version, 4, 0);
ae36393d
AL
3209
3210 my @usbdevices = PVE::QemuServer::USB::get_usb_devices($conf, $usbdesc->{format}, $MAX_USB_DEVICES, $usb_dev_features);
d40e5e18 3211 push @$devices, @usbdevices if @usbdevices;
1e3baf05 3212 # serial devices
bae179aa 3213 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
34978be3 3214 if (my $path = $conf->{"serial$i"}) {
9f9d2fb2
DM
3215 if ($path eq 'socket') {
3216 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3217 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
91b01bbb
WB
3218 # On aarch64, serial0 is the UART device. Qemu only allows
3219 # connecting UART devices via the '-serial' command line, as
3220 # the device has a fixed slot on the hardware...
3221 if ($arch eq 'aarch64' && $i == 0) {
3222 push @$devices, '-serial', "chardev:serial$i";
3223 } else {
3224 push @$devices, '-device', "isa-serial,chardev=serial$i";
3225 }
9f9d2fb2
DM
3226 } else {
3227 die "no such serial device\n" if ! -c $path;
3228 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3229 push @$devices, '-device', "isa-serial,chardev=serial$i";
3230 }
34978be3 3231 }
1e3baf05
DM
3232 }
3233
3234 # parallel devices
1989a89c 3235 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
34978be3 3236 if (my $path = $conf->{"parallel$i"}) {
19672434 3237 die "no such parallel device\n" if ! -c $path;
32e69805 3238 my $devtype = $path =~ m!^/dev/usb/lp! ? 'tty' : 'parport';
4c5dbaf6 3239 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
5bdcf937 3240 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
34978be3 3241 }
1e3baf05
DM
3242 }
3243
d5535a00
TL
3244 if (my $audio = conf_has_audio($conf)) {
3245
2e7b5925
AL
3246 my $audiopciaddr = print_pci_addr("audio0", $bridges, $arch, $machine_type);
3247
d5535a00
TL
3248 my $id = $audio->{dev_id};
3249 if ($audio->{dev} eq 'AC97') {
3250 push @$devices, '-device', "AC97,id=${id}${audiopciaddr}";
3251 } elsif ($audio->{dev} =~ /intel\-hda$/) {
3252 push @$devices, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
3253 push @$devices, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0";
3254 push @$devices, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1";
b3703d39 3255 } else {
d5535a00 3256 die "unkown audio device '$audio->{dev}', implement me!";
2e7b5925 3257 }
1448547f 3258
d5535a00 3259 push @$devices, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
2e7b5925 3260 }
19672434 3261
1e3baf05
DM
3262 my $sockets = 1;
3263 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3264 $sockets = $conf->{sockets} if $conf->{sockets};
3265
3266 my $cores = $conf->{cores} || 1;
3bd18e48 3267
de9d1e55 3268 my $maxcpus = $sockets * $cores;
76267728 3269
de9d1e55 3270 my $vcpus = $conf->{vcpus} ? $conf->{vcpus} : $maxcpus;
76267728 3271
de9d1e55
AD
3272 my $allowed_vcpus = $cpuinfo->{cpus};
3273
6965d5d1 3274 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
de9d1e55
AD
3275 if ($allowed_vcpus < $maxcpus);
3276
2ea5fb7e 3277 if($hotplug_features->{cpu} && min_version($machine_version, 2, 7)) {
1e3baf05 3278
69c81430
AD
3279 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3280 for (my $i = 2; $i <= $vcpus; $i++) {
3281 my $cpustr = print_cpu_device($conf,$i);
3282 push @$cmd, '-device', $cpustr;
3283 }
3284
3285 } else {
3286
3287 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3288 }
1e3baf05
DM
3289 push @$cmd, '-nodefaults';
3290
32baffb4 3291 my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
3b408e82 3292
0888fdce
DM
3293 my $bootindex_hash = {};
3294 my $i = 1;
3295 foreach my $o (split(//, $bootorder)) {
3296 $bootindex_hash->{$o} = $i*100;
3297 $i++;
afdb31d5 3298 }
3b408e82 3299
dbea4415 3300 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
1e3baf05 3301
6b64503e 3302 push @$cmd, '-no-acpi' if defined($conf->{acpi}) && $conf->{acpi} == 0;
1e3baf05 3303
6b64503e 3304 push @$cmd, '-no-reboot' if defined($conf->{reboot}) && $conf->{reboot} == 0;
1e3baf05 3305
84902837 3306 if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none'){
2ea5fb7e 3307 push @$devices, '-device', print_vga_device($conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
d036e418 3308 my $socket = PVE::QemuServer::Helpers::vnc_socket($vmid);
dc62a7fa 3309 push @$cmd, '-vnc', "unix:$socket,password";
b7be4ba9 3310 } else {
55655ebc 3311 push @$cmd, '-vga', 'none' if $vga->{type} eq 'none';
b7be4ba9
AD
3312 push @$cmd, '-nographic';
3313 }
3314
1e3baf05 3315 # time drift fix
6b64503e 3316 my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
1e3baf05 3317
8c559505 3318 my $useLocaltime = $conf->{localtime};
1e3baf05 3319
4317f69f
AD
3320 if ($winversion >= 5) { # windows
3321 $useLocaltime = 1 if !defined($conf->{localtime});
7a131888 3322
4317f69f
AD
3323 # use time drift fix when acpi is enabled
3324 if (!(defined($conf->{acpi}) && $conf->{acpi} == 0)) {
3325 $tdf = 1 if !defined($conf->{tdf});
462e8d19 3326 }
4317f69f 3327 }
462e8d19 3328
4317f69f
AD
3329 if ($winversion >= 6) {
3330 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3331 push @$cmd, '-no-hpet';
1e3baf05
DM
3332 }
3333
8c559505
DM
3334 push @$rtcFlags, 'driftfix=slew' if $tdf;
3335
85f0511d 3336 if (($conf->{startdate}) && ($conf->{startdate} ne 'now')) {
8c559505
DM
3337 push @$rtcFlags, "base=$conf->{startdate}";
3338 } elsif ($useLocaltime) {
3339 push @$rtcFlags, 'base=localtime';
3340 }
1e3baf05 3341
2ea5fb7e 3342 push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
519ed28c 3343
0567a4d5 3344 PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
370b05e7 3345
1e3baf05
DM
3346 push @$cmd, '-S' if $conf->{freeze};
3347
b20df606 3348 push @$cmd, '-k', $conf->{keyboard} if defined($conf->{keyboard});
1e3baf05 3349
48657158
MD
3350 my $guest_agent = parse_guest_agent($conf);
3351
3352 if ($guest_agent->{enabled}) {
d036e418 3353 my $qgasocket = PVE::QemuServer::Helpers::qmp_socket($vmid, 1);
ab6a046f 3354 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
48657158 3355
60f03a11 3356 if (!$guest_agent->{type} || $guest_agent->{type} eq 'virtio') {
48657158
MD
3357 my $pciaddr = print_pci_addr("qga0", $bridges, $arch, $machine_type);
3358 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3359 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3360 } elsif ($guest_agent->{type} eq 'isa') {
3361 push @$devices, '-device', "isa-serial,chardev=qga0";
3362 }
ab6a046f
AD
3363 }
3364
2cf61f33
SR
3365 my $rng = parse_rng($conf->{rng0}) if $conf->{rng0};
3366 if ($rng && &$version_guard(4, 1, 2)) {
3367 my $max_bytes = $rng->{max_bytes} // $rng_fmt->{max_bytes}->{default};
3368 my $period = $rng->{period} // $rng_fmt->{period}->{default};
3369
3370 my $limiter_str = "";
3371 if ($max_bytes) {
3372 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3373 }
3374
3375 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
3376 die "cannot create VirtIO RNG device: source file '$rng->{source}' doesn't exist\n"
3377 if ! -e $rng->{source};
3378
3379 my $rng_addr = print_pci_addr("rng0", $bridges, $arch, $machine_type);
3380
3381 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3382 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3383 }
3384
1d794448 3385 my $spice_port;
2fa3151e 3386
590e698c
DM
3387 if ($qxlnum) {
3388 if ($qxlnum > 1) {
ac087616 3389 if ($winversion){
590e698c 3390 for(my $i = 1; $i < $qxlnum; $i++){
2ea5fb7e 3391 push @$devices, '-device', print_vga_device($conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
590e698c
DM
3392 }
3393 } else {
3394 # assume other OS works like Linux
55655ebc
DC
3395 my ($ram, $vram) = ("134217728", "67108864");
3396 if ($vga->{memory}) {
3397 $ram = PVE::Tools::convert_size($qxlnum*4*$vga->{memory}, 'mb' => 'b');
3398 $vram = PVE::Tools::convert_size($qxlnum*2*$vga->{memory}, 'mb' => 'b');
3399 }
3400 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3401 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
2fa3151e
AD
3402 }
3403 }
3404
d559309f 3405 my $pciaddr = print_pci_addr("spice", $bridges, $arch, $machine_type);
95a4b4a9 3406
af0eba7e 3407 my $pfamily = PVE::Tools::get_host_address_family($nodename);
91152441
WB
3408 my @nodeaddrs = PVE::Tools::getaddrinfo_all('localhost', family => $pfamily);
3409 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
4d316a63
AL
3410
3411 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3412 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3413 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3414
91152441
WB
3415 my $localhost = PVE::Network::addr_to_ip($nodeaddrs[0]->{addr});
3416 $spice_port = PVE::Tools::next_spice_port($pfamily, $localhost);
943340a6 3417
caab114a
TL
3418 my $spice_enhancement = PVE::JSONSchema::parse_property_string($spice_enhancements_fmt, $conf->{spice_enhancements} // '');
3419 if ($spice_enhancement->{foldersharing}) {
3420 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3421 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3422 }
c4df18db 3423
caab114a
TL
3424 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3425 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}" if $spice_enhancement->{videostreaming};
3426 push @$devices, '-spice', "$spice_opts";
1011b570
DM
3427 }
3428
8d9ae0d2
DM
3429 # enable balloon by default, unless explicitly disabled
3430 if (!defined($conf->{balloon}) || $conf->{balloon}) {
d559309f 3431 $pciaddr = print_pci_addr("balloon0", $bridges, $arch, $machine_type);
8d9ae0d2
DM
3432 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3433 }
1e3baf05 3434
0ea9541d
DM
3435 if ($conf->{watchdog}) {
3436 my $wdopts = parse_watchdog($conf->{watchdog});
d559309f 3437 $pciaddr = print_pci_addr("watchdog", $bridges, $arch, $machine_type);
0a40e8ea 3438 my $watchdog = $wdopts->{model} || 'i6300esb';
5bdcf937
AD
3439 push @$devices, '-device', "$watchdog$pciaddr";
3440 push @$devices, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
0ea9541d
DM
3441 }
3442
1e3baf05 3443 my $vollist = [];
941e0c42 3444 my $scsicontroller = {};
26ee04b6 3445 my $ahcicontroller = {};
cdd20088 3446 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : $defaults->{scsihw};
1e3baf05 3447
5881b913
DM
3448 # Add iscsi initiator name if available
3449 if (my $initiator = get_initiator_name()) {
3450 push @$devices, '-iscsi', "initiator-name=$initiator";
3451 }
3452
1e3baf05
DM
3453 foreach_drive($conf, sub {
3454 my ($ds, $drive) = @_;
3455
ff1a2432 3456 if (PVE::Storage::parse_volume_id($drive->{file}, 1)) {
1e3baf05 3457 push @$vollist, $drive->{file};
ff1a2432 3458 }
afdb31d5 3459
4dcce9ee
TL
3460 # ignore efidisk here, already added in bios/fw handling code above
3461 return if $drive->{interface} eq 'efidisk';
3462
1e3baf05 3463 $use_virtio = 1 if $ds =~ m/^virtio/;
3b408e82
DM
3464
3465 if (drive_is_cdrom ($drive)) {
3466 if ($bootindex_hash->{d}) {
3467 $drive->{bootindex} = $bootindex_hash->{d};
3468 $bootindex_hash->{d} += 1;
3469 }
3470 } else {
3471 if ($bootindex_hash->{c}) {
3472 $drive->{bootindex} = $bootindex_hash->{c} if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds);
3473 $bootindex_hash->{c} += 1;
3474 }
3475 }
3476
51f492cd
AD
3477 if($drive->{interface} eq 'virtio'){
3478 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread};
3479 }
3480
941e0c42 3481 if ($drive->{interface} eq 'scsi') {
cdd20088 3482
ee034f5c 3483 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
6731a4cf 3484
b8fb1c03
SR
3485 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3486 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3487
d559309f 3488 $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges, $arch, $machine_type);
a1b7d579 3489 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ? "virtio-scsi-pci" : $scsihw;
fc8b40fd
AD
3490
3491 my $iothread = '';
3492 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{iothread}){
3493 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3494 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
e7a5104d
DC
3495 } elsif ($drive->{iothread}) {
3496 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
fc8b40fd
AD
3497 }
3498
6e11f143
AD
3499 my $queues = '';
3500 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{queues}){
3501 $queues = ",num_queues=$drive->{queues}";
370b05e7 3502 }
6e11f143
AD
3503
3504 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
cdd20088 3505 $scsicontroller->{$controller}=1;
941e0c42 3506 }
3b408e82 3507
26ee04b6 3508 if ($drive->{interface} eq 'sata') {
e0fd2b2f 3509 my $controller = int($drive->{index} / $PVE::QemuServer::Drive::MAX_SATA_DISKS);
d559309f 3510 $pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $machine_type);
5bdcf937 3511 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
26ee04b6
DA
3512 $ahcicontroller->{$controller}=1;
3513 }
46f58b5f 3514
776c5f50 3515 my $drive_cmd = print_drive_commandline_full($storecfg, $vmid, $drive);
15b21acc 3516 push @$devices, '-drive',$drive_cmd;
d559309f 3517 push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
1e3baf05
DM
3518 });
3519
cc4d6182 3520 for (my $i = 0; $i < $MAX_NETS; $i++) {
5f0c4c32 3521 next if !$conf->{"net$i"};
cc4d6182
DA
3522 my $d = parse_net($conf->{"net$i"});
3523 next if !$d;
1e3baf05 3524
cc4d6182 3525 $use_virtio = 1 if $d->{model} eq 'virtio';
1e3baf05 3526
cc4d6182
DA
3527 if ($bootindex_hash->{n}) {
3528 $d->{bootindex} = $bootindex_hash->{n};
3529 $bootindex_hash->{n} += 1;
3530 }
1e3baf05 3531
d559309f 3532 my $netdevfull = print_netdev_full($vmid, $conf, $arch, $d, "net$i");
5bdcf937
AD
3533 push @$devices, '-netdev', $netdevfull;
3534
d559309f 3535 my $netdevicefull = print_netdevice_full($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
5bdcf937
AD
3536 push @$devices, '-device', $netdevicefull;
3537 }
1e3baf05 3538
6dbcb073
DC
3539 if ($conf->{ivshmem}) {
3540 my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
e3c27a6a 3541
6dbcb073
DC
3542 my $bus;
3543 if ($q35) {
3544 $bus = print_pcie_addr("ivshmem");
3545 } else {
3546 $bus = print_pci_addr("ivshmem", $bridges, $arch, $machine_type);
3547 }
e3c27a6a
TL
3548
3549 my $ivshmem_name = $ivshmem->{name} // $vmid;
3550 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3551
6dbcb073
DC
3552 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
3553 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
3554 }
3555
2513b862
DC
3556 # pci.4 is nested in pci.1
3557 $bridges->{1} = 1 if $bridges->{4};
3558
db656e5f
DM
3559 if (!$q35) {
3560 # add pci bridges
2ea5fb7e 3561 if (min_version($machine_version, 2, 3)) {
fc79e813
AD
3562 $bridges->{1} = 1;
3563 $bridges->{2} = 1;
3564 }
3565
6731a4cf
AD
3566 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3567
2513b862
DC
3568 }
3569
3570 for my $k (sort {$b cmp $a} keys %$bridges) {
3571 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
3572 $pciaddr = print_pci_addr("pci.$k", undef, $arch, $machine_type);
3573 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3574 if ($q35) {
3575 # add after -readconfig pve-q35.cfg
3576 splice @$devices, 2, 0, '-device', $devstr;
3577 } else {
3578 unshift @$devices, '-device', $devstr if $k > 0;
f8e83f05 3579 }
19672434
DM
3580 }
3581
ac0077cc
SR
3582 if (!$kvm) {
3583 push @$machineFlags, 'accel=tcg';
3584 }
3585
3586 my $machine_type_min = $machine_type;
3587 if ($add_pve_version) {
3588 $machine_type_min =~ s/\+pve\d+$//;
3589 $machine_type_min .= "+pve$required_pve_version";
3590 }
3591 push @$machineFlags, "type=${machine_type_min}";
3592
5bdcf937 3593 push @$cmd, @$devices;
be190583 3594 push @$cmd, '-rtc', join(',', @$rtcFlags)
8c559505 3595 if scalar(@$rtcFlags);
be190583 3596 push @$cmd, '-machine', join(',', @$machineFlags)
8c559505
DM
3597 if scalar(@$machineFlags);
3598 push @$cmd, '-global', join(',', @$globalFlags)
3599 if scalar(@$globalFlags);
3600
7ceade4c
DC
3601 if (my $vmstate = $conf->{vmstate}) {
3602 my $statepath = PVE::Storage::path($storecfg, $vmstate);
24d1f93a 3603 push @$vollist, $vmstate;
7ceade4c 3604 push @$cmd, '-loadstate', $statepath;
b85666cf 3605 print "activating and using '$vmstate' as vmstate\n";
7ceade4c
DC
3606 }
3607
76350670
DC
3608 # add custom args
3609 if ($conf->{args}) {
3610 my $aa = PVE::Tools::split_args($conf->{args});
3611 push @$cmd, @$aa;
3612 }
3613
1d794448 3614 return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
1e3baf05 3615}
19672434 3616
943340a6 3617sub spice_port {
1011b570 3618 my ($vmid) = @_;
943340a6 3619
0a13e08e 3620 my $res = mon_cmd($vmid, 'query-spice');
943340a6
DM
3621
3622 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
1011b570
DM
3623}
3624
86fdcfb2
DA
3625sub vm_devices_list {
3626 my ($vmid) = @_;
3627
0a13e08e 3628 my $res = mon_cmd($vmid, 'query-pci');
f721624b 3629 my $devices_to_check = [];
ceea9078
DM
3630 my $devices = {};
3631 foreach my $pcibus (@$res) {
f721624b
DC
3632 push @$devices_to_check, @{$pcibus->{devices}},
3633 }
3634
3635 while (@$devices_to_check) {
3636 my $to_check = [];
3637 for my $d (@$devices_to_check) {
3638 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3639 next if !$d->{'pci_bridge'};
3640
3641 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices}});
3642 push @$to_check, @{$d->{'pci_bridge'}->{devices}};
f78cc802 3643 }
f721624b 3644 $devices_to_check = $to_check;
f78cc802
AD
3645 }
3646
0a13e08e 3647 my $resblock = mon_cmd($vmid, 'query-block');
f78cc802
AD
3648 foreach my $block (@$resblock) {
3649 if($block->{device} =~ m/^drive-(\S+)/){
3650 $devices->{$1} = 1;
1dc4f496
DM
3651 }
3652 }
86fdcfb2 3653
0a13e08e 3654 my $resmice = mon_cmd($vmid, 'query-mice');
3d7389fe
DM
3655 foreach my $mice (@$resmice) {
3656 if ($mice->{name} eq 'QEMU HID Tablet') {
3657 $devices->{tablet} = 1;
3658 last;
3659 }
3660 }
3661
deb091c5
DC
3662 # for usb devices there is no query-usb
3663 # but we can iterate over the entries in
3664 # qom-list path=/machine/peripheral
0a13e08e 3665 my $resperipheral = mon_cmd($vmid, 'qom-list', path => '/machine/peripheral');
deb091c5
DC
3666 foreach my $per (@$resperipheral) {
3667 if ($per->{name} =~ m/^usb\d+$/) {
3668 $devices->{$per->{name}} = 1;
3669 }
3670 }
3671
1dc4f496 3672 return $devices;
86fdcfb2
DA
3673}
3674
ec21aa11 3675sub vm_deviceplug {
d559309f 3676 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
ae57f6b3 3677
3392d6ca 3678 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
db656e5f 3679
95d6343b
DA
3680 my $devices_list = vm_devices_list($vmid);
3681 return 1 if defined($devices_list->{$deviceid});
3682
d559309f 3683 qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
fee46675 3684
3d7389fe 3685 if ($deviceid eq 'tablet') {
fee46675 3686
d559309f
WB
3687 qemu_deviceadd($vmid, print_tabletdevice_full($conf, $arch));
3688
3689 } elsif ($deviceid eq 'keyboard') {
3690
3691 qemu_deviceadd($vmid, print_keyboarddevice_full($conf, $arch));
3d7389fe 3692
4eb68604
DC
3693 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3694
f745762b
DC
3695 die "usb hotplug currently not reliable\n";
3696 # since we can't reliably hot unplug all added usb devices
3697 # and usb passthrough disables live migration
3698 # we disable usb hotplugging for now
4eb68604
DC
3699 qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
3700
fee46675 3701 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
40f28a9f 3702
22de899a
AD
3703 qemu_iothread_add($vmid, $deviceid, $device);
3704
fee46675 3705 qemu_driveadd($storecfg, $vmid, $device);
d559309f 3706 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, $arch, $machine_type);
fee46675 3707
5e5dcb73 3708 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
3709 eval { qemu_deviceaddverify($vmid, $deviceid); };
3710 if (my $err = $@) {
63c2da2f
DM
3711 eval { qemu_drivedel($vmid, $deviceid); };
3712 warn $@ if $@;
fee46675 3713 die $err;
5e5dcb73 3714 }
cfc817c7 3715
2733141c 3716 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
fee46675 3717
fc8b40fd 3718
cdd20088 3719 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
d559309f 3720 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
a1b7d579 3721 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ? "virtio-scsi-pci" : $scsihw;
2733141c
AD
3722
3723 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
fee46675 3724
fc8b40fd
AD
3725 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread}) {
3726 qemu_iothread_add($vmid, $deviceid, $device);
3727 $devicefull .= ",iothread=iothread-$deviceid";
3728 }
3729
6e11f143
AD
3730 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues}) {
3731 $devicefull .= ",num_queues=$device->{queues}";
3732 }
3733
cfc817c7 3734 qemu_deviceadd($vmid, $devicefull);
fee46675 3735 qemu_deviceaddverify($vmid, $deviceid);
cfc817c7 3736
fee46675
DM
3737 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3738
d559309f 3739 qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device, $arch, $machine_type);
fee46675 3740 qemu_driveadd($storecfg, $vmid, $device);
a1b7d579 3741
d559309f 3742 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, $arch, $machine_type);
fee46675
DM
3743 eval { qemu_deviceadd($vmid, $devicefull); };
3744 if (my $err = $@) {
63c2da2f
DM
3745 eval { qemu_drivedel($vmid, $deviceid); };
3746 warn $@ if $@;
fee46675 3747 die $err;
a4f091a0 3748 }
a4f091a0 3749
fee46675
DM
3750 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3751
95d3be58 3752 return undef if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
8718099c 3753
3392d6ca 3754 my $machine_type = PVE::QemuServer::Machine::qemu_machine_pxe($vmid, $conf);
95d3be58
DC
3755 my $use_old_bios_files = undef;
3756 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
8718099c 3757
95d3be58
DC
3758 my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
3759 qemu_deviceadd($vmid, $netdevicefull);
79046fd1
DC
3760 eval {
3761 qemu_deviceaddverify($vmid, $deviceid);
3762 qemu_set_link_status($vmid, $deviceid, !$device->{link_down});
3763 };
fee46675
DM
3764 if (my $err = $@) {
3765 eval { qemu_netdevdel($vmid, $deviceid); };
3766 warn $@ if $@;
3767 die $err;
95d3be58 3768 }
2630d2a9 3769
fee46675 3770 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
b467f79a 3771
40f28a9f 3772 my $bridgeid = $2;
d559309f 3773 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
40f28a9f 3774 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
a1b7d579 3775
40f28a9f 3776 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
3777 qemu_deviceaddverify($vmid, $deviceid);
3778
3779 } else {
a1b7d579 3780 die "can't hotplug device '$deviceid'\n";
40f28a9f
AD
3781 }
3782
5e5dcb73 3783 return 1;
a4dea331
DA
3784}
3785
3eec5767 3786# fixme: this should raise exceptions on error!
ec21aa11 3787sub vm_deviceunplug {
f19d1c47 3788 my ($vmid, $conf, $deviceid) = @_;
873c2d69 3789
95d6343b
DA
3790 my $devices_list = vm_devices_list($vmid);
3791 return 1 if !defined($devices_list->{$deviceid});
3792
63c2da2f
DM
3793 die "can't unplug bootdisk" if $conf->{bootdisk} && $conf->{bootdisk} eq $deviceid;
3794
d559309f 3795 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
63c2da2f 3796
3d7389fe 3797 qemu_devicedel($vmid, $deviceid);
3d7389fe 3798
4eb68604
DC
3799 } elsif ($deviceid =~ m/^usb\d+$/) {
3800
f745762b
DC
3801 die "usb hotplug currently not reliable\n";
3802 # when unplugging usb devices this way,
3803 # there may be remaining usb controllers/hubs
3804 # so we disable it for now
4eb68604
DC
3805 qemu_devicedel($vmid, $deviceid);
3806 qemu_devicedelverify($vmid, $deviceid);
3807
63c2da2f 3808 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
f19d1c47 3809
5e5dcb73 3810 qemu_devicedel($vmid, $deviceid);
63c2da2f
DM
3811 qemu_devicedelverify($vmid, $deviceid);
3812 qemu_drivedel($vmid, $deviceid);
22de899a
AD
3813 qemu_iothread_del($conf, $vmid, $deviceid);
3814
2733141c 3815 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
a1b7d579 3816
63c2da2f 3817 qemu_devicedel($vmid, $deviceid);
8ce30dde 3818 qemu_devicedelverify($vmid, $deviceid);
fc8b40fd 3819 qemu_iothread_del($conf, $vmid, $deviceid);
a1b7d579 3820
63c2da2f 3821 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
cfc817c7 3822
63c2da2f
DM
3823 qemu_devicedel($vmid, $deviceid);
3824 qemu_drivedel($vmid, $deviceid);
a1b7d579 3825 qemu_deletescsihw($conf, $vmid, $deviceid);
8ce30dde 3826
63c2da2f 3827 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
a4f091a0 3828
2630d2a9 3829 qemu_devicedel($vmid, $deviceid);
63c2da2f
DM
3830 qemu_devicedelverify($vmid, $deviceid);
3831 qemu_netdevdel($vmid, $deviceid);
3832
3833 } else {
3834 die "can't unplug device '$deviceid'\n";
2630d2a9
DA
3835 }
3836
5e5dcb73
DA
3837 return 1;
3838}
3839
3840sub qemu_deviceadd {
3841 my ($vmid, $devicefull) = @_;
873c2d69 3842
d695b5b7
AD
3843 $devicefull = "driver=".$devicefull;
3844 my %options = split(/[=,]/, $devicefull);
f19d1c47 3845
0a13e08e 3846 mon_cmd($vmid, "device_add" , %options);
5e5dcb73 3847}
afdb31d5 3848
5e5dcb73 3849sub qemu_devicedel {
fee46675 3850 my ($vmid, $deviceid) = @_;
63c2da2f 3851
0a13e08e 3852 my $ret = mon_cmd($vmid, "device_del", id => $deviceid);
5e5dcb73
DA
3853}
3854
22de899a
AD
3855sub qemu_iothread_add {
3856 my($vmid, $deviceid, $device) = @_;
3857
3858 if ($device->{iothread}) {
3859 my $iothreads = vm_iothreads_list($vmid);
3860 qemu_objectadd($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3861 }
3862}
3863
3864sub qemu_iothread_del {
3865 my($conf, $vmid, $deviceid) = @_;
3866
7820eae4
DC
3867 my $confid = $deviceid;
3868 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
3869 $confid = 'scsi' . $1;
3870 }
3871 my $device = parse_drive($confid, $conf->{$confid});
22de899a
AD
3872 if ($device->{iothread}) {
3873 my $iothreads = vm_iothreads_list($vmid);
3874 qemu_objectdel($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3875 }
3876}
3877
4d3f29ed
AD
3878sub qemu_objectadd {
3879 my($vmid, $objectid, $qomtype) = @_;
3880
0a13e08e 3881 mon_cmd($vmid, "object-add", id => $objectid, "qom-type" => $qomtype);
4d3f29ed
AD
3882
3883 return 1;
3884}
3885
3886sub qemu_objectdel {
3887 my($vmid, $objectid) = @_;
3888
0a13e08e 3889 mon_cmd($vmid, "object-del", id => $objectid);
4d3f29ed
AD
3890
3891 return 1;
3892}
3893
5e5dcb73 3894sub qemu_driveadd {
fee46675 3895 my ($storecfg, $vmid, $device) = @_;
5e5dcb73 3896
776c5f50 3897 my $drive = print_drive_commandline_full($storecfg, $vmid, $device);
7a69fc3c 3898 $drive =~ s/\\/\\\\/g;
0a13e08e 3899 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_add auto \"$drive\"");
fee46675 3900
5e5dcb73 3901 # If the command succeeds qemu prints: "OK"
fee46675
DM
3902 return 1 if $ret =~ m/OK/s;
3903
3904 die "adding drive failed: $ret\n";
5e5dcb73 3905}
afdb31d5 3906
5e5dcb73
DA
3907sub qemu_drivedel {
3908 my($vmid, $deviceid) = @_;
873c2d69 3909
0a13e08e 3910 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-$deviceid");
5e5dcb73 3911 $ret =~ s/^\s+//;
a1b7d579 3912
63c2da2f 3913 return 1 if $ret eq "";
a1b7d579 3914
63c2da2f 3915 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
a1b7d579
DM
3916 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3917
63c2da2f 3918 die "deleting drive $deviceid failed : $ret\n";
5e5dcb73 3919}
f19d1c47 3920
5e5dcb73 3921sub qemu_deviceaddverify {
fee46675 3922 my ($vmid, $deviceid) = @_;
873c2d69 3923
5e5dcb73
DA
3924 for (my $i = 0; $i <= 5; $i++) {
3925 my $devices_list = vm_devices_list($vmid);
3926 return 1 if defined($devices_list->{$deviceid});
3927 sleep 1;
afdb31d5 3928 }
fee46675
DM
3929
3930 die "error on hotplug device '$deviceid'\n";
5e5dcb73 3931}
afdb31d5 3932
5e5dcb73
DA
3933
3934sub qemu_devicedelverify {
63c2da2f
DM
3935 my ($vmid, $deviceid) = @_;
3936
a1b7d579 3937 # need to verify that the device is correctly removed as device_del
63c2da2f 3938 # is async and empty return is not reliable
5e5dcb73 3939
5e5dcb73
DA
3940 for (my $i = 0; $i <= 5; $i++) {
3941 my $devices_list = vm_devices_list($vmid);
3942 return 1 if !defined($devices_list->{$deviceid});
3943 sleep 1;
afdb31d5 3944 }
63c2da2f
DM
3945
3946 die "error on hot-unplugging device '$deviceid'\n";
873c2d69
DA
3947}
3948
cdd20088 3949sub qemu_findorcreatescsihw {
d559309f 3950 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
cfc817c7 3951
ee034f5c 3952 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
2733141c
AD
3953
3954 my $scsihwid="$controller_prefix$controller";
cfc817c7
DA
3955 my $devices_list = vm_devices_list($vmid);
3956
cdd20088 3957 if(!defined($devices_list->{$scsihwid})) {
d559309f 3958 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
cfc817c7 3959 }
fee46675 3960
cfc817c7
DA
3961 return 1;
3962}
3963
8ce30dde
AD
3964sub qemu_deletescsihw {
3965 my ($conf, $vmid, $opt) = @_;
3966
3967 my $device = parse_drive($opt, $conf->{$opt});
3968
a1511b3c 3969 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
2733141c
AD
3970 vm_deviceunplug($vmid, $conf, "virtioscsi$device->{index}");
3971 return 1;
3972 }
3973
ee034f5c 3974 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
8ce30dde
AD
3975
3976 my $devices_list = vm_devices_list($vmid);
3977 foreach my $opt (keys %{$devices_list}) {
e0fd2b2f
FE
3978 if (is_valid_drivename($opt)) {
3979 my $drive = parse_drive($opt, $conf->{$opt});
8ce30dde
AD
3980 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3981 return 1;
3982 }
3983 }
3984 }
3985
3986 my $scsihwid="scsihw$controller";
3987
3988 vm_deviceunplug($vmid, $conf, $scsihwid);
3989
3990 return 1;
3991}
3992
281fedb3 3993sub qemu_add_pci_bridge {
d559309f 3994 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
40f28a9f
AD
3995
3996 my $bridges = {};
281fedb3
DM
3997
3998 my $bridgeid;
3999
d559309f 4000 print_pci_addr($device, $bridges, $arch, $machine_type);
40f28a9f
AD
4001
4002 while (my ($k, $v) = each %$bridges) {
4003 $bridgeid = $k;
4004 }
fee46675 4005 return 1 if !defined($bridgeid) || $bridgeid < 1;
281fedb3 4006
40f28a9f
AD
4007 my $bridge = "pci.$bridgeid";
4008 my $devices_list = vm_devices_list($vmid);
4009
281fedb3 4010 if (!defined($devices_list->{$bridge})) {
d559309f 4011 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
40f28a9f 4012 }
281fedb3 4013
40f28a9f
AD
4014 return 1;
4015}
4016
25088687
DM
4017sub qemu_set_link_status {
4018 my ($vmid, $device, $up) = @_;
4019
0a13e08e 4020 mon_cmd($vmid, "set_link", name => $device,
25088687
DM
4021 up => $up ? JSON::true : JSON::false);
4022}
4023
2630d2a9 4024sub qemu_netdevadd {
d559309f 4025 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
2630d2a9 4026
d559309f 4027 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
73aa03b8 4028 my %options = split(/[=,]/, $netdev);
2630d2a9 4029
0a13e08e 4030 mon_cmd($vmid, "netdev_add", %options);
73aa03b8 4031 return 1;
2630d2a9
DA
4032}
4033
4034sub qemu_netdevdel {
4035 my ($vmid, $deviceid) = @_;
4036
0a13e08e 4037 mon_cmd($vmid, "netdev_del", id => $deviceid);
2630d2a9
DA
4038}
4039
16521d63 4040sub qemu_usb_hotplug {
d559309f 4041 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
16521d63
DC
4042
4043 return if !$device;
4044
4045 # remove the old one first
4046 vm_deviceunplug($vmid, $conf, $deviceid);
4047
4048 # check if xhci controller is necessary and available
4049 if ($device->{usb3}) {
4050
4051 my $devicelist = vm_devices_list($vmid);
4052
4053 if (!$devicelist->{xhci}) {
d559309f 4054 my $pciaddr = print_pci_addr("xhci", undef, $arch, $machine_type);
16521d63
DC
4055 qemu_deviceadd($vmid, "nec-usb-xhci,id=xhci$pciaddr");
4056 }
4057 }
4058 my $d = parse_usb_device($device->{host});
4059 $d->{usb3} = $device->{usb3};
4060
4061 # add the new one
d559309f 4062 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
16521d63
DC
4063}
4064
838776ab 4065sub qemu_cpu_hotplug {
8edc9c08 4066 my ($vmid, $conf, $vcpus) = @_;
838776ab 4067
3392d6ca 4068 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
1e881b75 4069
8edc9c08
AD
4070 my $sockets = 1;
4071 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4072 $sockets = $conf->{sockets} if $conf->{sockets};
4073 my $cores = $conf->{cores} || 1;
4074 my $maxcpus = $sockets * $cores;
838776ab 4075
8edc9c08 4076 $vcpus = $maxcpus if !$vcpus;
3a11fadb 4077
8edc9c08
AD
4078 die "you can't add more vcpus than maxcpus\n"
4079 if $vcpus > $maxcpus;
3a11fadb 4080
8edc9c08 4081 my $currentvcpus = $conf->{vcpus} || $maxcpus;
1e881b75 4082
eba3e64d 4083 if ($vcpus < $currentvcpus) {
1e881b75 4084
2ea5fb7e 4085 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
1e881b75
AD
4086
4087 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4088 qemu_devicedel($vmid, "cpu$i");
4089 my $retry = 0;
4090 my $currentrunningvcpus = undef;
4091 while (1) {
65af8c31 4092 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
1e881b75 4093 last if scalar(@{$currentrunningvcpus}) == $i-1;
961af8a3 4094 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
1e881b75
AD
4095 $retry++;
4096 sleep 1;
4097 }
4098 #update conf after each succesfull cpu unplug
4099 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4100 PVE::QemuConfig->write_config($vmid, $conf);
4101 }
4102 } else {
961af8a3 4103 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
1e881b75
AD
4104 }
4105
4106 return;
4107 }
838776ab 4108
65af8c31 4109 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
961af8a3 4110 die "vcpus in running vm does not match its configuration\n"
8edc9c08 4111 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
838776ab 4112
2ea5fb7e 4113 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
eba3e64d
AD
4114
4115 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4116 my $cpustr = print_cpu_device($conf, $i);
4117 qemu_deviceadd($vmid, $cpustr);
4118
4119 my $retry = 0;
4120 my $currentrunningvcpus = undef;
4121 while (1) {
65af8c31 4122 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
eba3e64d 4123 last if scalar(@{$currentrunningvcpus}) == $i;
961af8a3 4124 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
eba3e64d
AD
4125 sleep 1;
4126 $retry++;
4127 }
4128 #update conf after each succesfull cpu hotplug
4129 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4130 PVE::QemuConfig->write_config($vmid, $conf);
4131 }
4132 } else {
4133
4134 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
0a13e08e 4135 mon_cmd($vmid, "cpu-add", id => int($i));
eba3e64d 4136 }
838776ab
AD
4137 }
4138}
4139
affd2f88 4140sub qemu_block_set_io_throttle {
277ca170
WB
4141 my ($vmid, $deviceid,
4142 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
9196a8ec
WB
4143 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4144 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4145 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
affd2f88 4146
f3f323a3
AD
4147 return if !check_running($vmid) ;
4148
0a13e08e 4149 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
277ca170
WB
4150 bps => int($bps),
4151 bps_rd => int($bps_rd),
4152 bps_wr => int($bps_wr),
4153 iops => int($iops),
4154 iops_rd => int($iops_rd),
4155 iops_wr => int($iops_wr),
4156 bps_max => int($bps_max),
4157 bps_rd_max => int($bps_rd_max),
4158 bps_wr_max => int($bps_wr_max),
4159 iops_max => int($iops_max),
4160 iops_rd_max => int($iops_rd_max),
9196a8ec
WB
4161 iops_wr_max => int($iops_wr_max),
4162 bps_max_length => int($bps_max_length),
4163 bps_rd_max_length => int($bps_rd_max_length),
4164 bps_wr_max_length => int($bps_wr_max_length),
4165 iops_max_length => int($iops_max_length),
4166 iops_rd_max_length => int($iops_rd_max_length),
4167 iops_wr_max_length => int($iops_wr_max_length),
277ca170 4168 );
f3f323a3 4169
affd2f88
AD
4170}
4171
f5eb281a 4172# old code, only used to shutdown old VM after update
dab36e1e
DM
4173sub __read_avail {
4174 my ($fh, $timeout) = @_;
4175
4176 my $sel = new IO::Select;
4177 $sel->add($fh);
4178
4179 my $res = '';
4180 my $buf;
4181
4182 my @ready;
4183 while (scalar (@ready = $sel->can_read($timeout))) {
4184 my $count;
4185 if ($count = $fh->sysread($buf, 8192)) {
4186 if ($buf =~ /^(.*)\(qemu\) $/s) {
4187 $res .= $1;
4188 last;
4189 } else {
4190 $res .= $buf;
4191 }
4192 } else {
4193 if (!defined($count)) {
4194 die "$!\n";
4195 }
4196 last;
4197 }
4198 }
4199
4200 die "monitor read timeout\n" if !scalar(@ready);
f5eb281a 4201
dab36e1e
DM
4202 return $res;
4203}
4204
c1175c92
AD
4205sub qemu_block_resize {
4206 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4207
ed221350 4208 my $running = check_running($vmid);
c1175c92 4209
7246e8f9 4210 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
c1175c92
AD
4211
4212 return if !$running;
4213
375db731
FE
4214 my $padding = (1024 - $size % 1024) % 1024;
4215 $size = $size + $padding;
4216
0a13e08e 4217 mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
c1175c92
AD
4218
4219}
4220
1ab0057c
AD
4221sub qemu_volume_snapshot {
4222 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4223
ed221350 4224 my $running = check_running($vmid);
1ab0057c 4225
e5eaa028 4226 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
0a13e08e 4227 mon_cmd($vmid, 'blockdev-snapshot-internal-sync', device => $deviceid, name => $snap);
e5eaa028
WL
4228 } else {
4229 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4230 }
1ab0057c
AD
4231}
4232
fc46aff9
AD
4233sub qemu_volume_snapshot_delete {
4234 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4235
ed221350 4236 my $running = check_running($vmid);
fc46aff9 4237
a2f1554b
AD
4238 if($running) {
4239
4240 $running = undef;
4241 my $conf = PVE::QemuConfig->load_config($vmid);
4242 foreach_drive($conf, sub {
4243 my ($ds, $drive) = @_;
4244 $running = 1 if $drive->{file} eq $volid;
4245 });
4246 }
4247
1ef7592f 4248 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
0a13e08e 4249 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync', device => $deviceid, name => $snap);
1ef7592f
AD
4250 } else {
4251 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4252 }
fc46aff9
AD
4253}
4254
264e519f
DM
4255sub set_migration_caps {
4256 my ($vmid) = @_;
a89fded1 4257
8b8345f3 4258 my $cap_ref = [];
a89fded1
AD
4259
4260 my $enabled_cap = {
8b8345f3 4261 "auto-converge" => 1,
0b0a47e8 4262 "xbzrle" => 1,
8b8345f3
DM
4263 "x-rdma-pin-all" => 0,
4264 "zero-blocks" => 0,
b62532e4 4265 "compress" => 0
a89fded1
AD
4266 };
4267
0a13e08e 4268 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
a89fded1 4269
8b8345f3 4270 for my $supported_capability (@$supported_capabilities) {
b463a3ce
SP
4271 push @$cap_ref, {
4272 capability => $supported_capability->{capability},
22430fa2
DM
4273 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4274 };
a89fded1
AD
4275 }
4276
0a13e08e 4277 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
8b8345f3 4278}
a89fded1 4279
81d95ae1 4280my $fast_plug_option = {
7498eb64 4281 'lock' => 1,
81d95ae1 4282 'name' => 1,
a1b7d579 4283 'onboot' => 1,
81d95ae1
DM
4284 'shares' => 1,
4285 'startup' => 1,
b0ec896e 4286 'description' => 1,
ec647db4 4287 'protection' => 1,
8cad5e9b 4288 'vmstatestorage' => 1,
9e784b11 4289 'hookscript' => 1,
b8e7068a 4290 'tags' => 1,
81d95ae1
DM
4291};
4292
3a11fadb
DM
4293# hotplug changes in [PENDING]
4294# $selection hash can be used to only apply specified options, for
4295# example: { cores => 1 } (only apply changed 'cores')
4296# $errors ref is used to return error messages
c427973b 4297sub vmconfig_hotplug_pending {
3a11fadb 4298 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
c427973b 4299
8e90138a 4300 my $defaults = load_defaults();
045749f2
TL
4301 my $arch = get_vm_arch($conf);
4302 my $machine_type = get_vm_machine($conf, undef, $arch);
c427973b
DM
4303
4304 # commit values which do not have any impact on running VM first
3a11fadb
DM
4305 # Note: those option cannot raise errors, we we do not care about
4306 # $selection and always apply them.
4307
4308 my $add_error = sub {
4309 my ($opt, $msg) = @_;
4310 $errors->{$opt} = "hotplug problem - $msg";
4311 };
c427973b
DM
4312
4313 my $changes = 0;
4314 foreach my $opt (keys %{$conf->{pending}}) { # add/change
81d95ae1 4315 if ($fast_plug_option->{$opt}) {
c427973b
DM
4316 $conf->{$opt} = $conf->{pending}->{$opt};
4317 delete $conf->{pending}->{$opt};
4318 $changes = 1;
4319 }
4320 }
4321
4322 if ($changes) {
ffda963f 4323 PVE::QemuConfig->write_config($vmid, $conf);
c427973b
DM
4324 }
4325
b3c2bdd1 4326 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
c427973b 4327
98bc3aeb 4328 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 4329 foreach my $opt (sort keys %$pending_delete_hash) {
3a11fadb 4330 next if $selection && !$selection->{$opt};
d321c4a9 4331 my $force = $pending_delete_hash->{$opt}->{force};
3a11fadb 4332 eval {
51a6f637
AD
4333 if ($opt eq 'hotplug') {
4334 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4335 } elsif ($opt eq 'tablet') {
b3c2bdd1 4336 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4337 if ($defaults->{tablet}) {
d559309f
WB
4338 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4339 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4340 if $arch eq 'aarch64';
3a11fadb 4341 } else {
d559309f
WB
4342 vm_deviceunplug($vmid, $conf, 'tablet');
4343 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4344 }
4eb68604 4345 } elsif ($opt =~ m/^usb\d+/) {
f745762b
DC
4346 die "skip\n";
4347 # since we cannot reliably hot unplug usb devices
4348 # we are disabling it
4eb68604
DC
4349 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4350 vm_deviceunplug($vmid, $conf, $opt);
8edc9c08 4351 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4352 die "skip\n" if !$hotplug_features->{cpu};
8edc9c08 4353 qemu_cpu_hotplug($vmid, $conf, undef);
9c2f7069 4354 } elsif ($opt eq 'balloon') {
81d95ae1 4355 # enable balloon device is not hotpluggable
75b51053
DC
4356 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4357 # here we reset the ballooning value to memory
4358 my $balloon = $conf->{memory} || $defaults->{memory};
0a13e08e 4359 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
81d95ae1
DM
4360 } elsif ($fast_plug_option->{$opt}) {
4361 # do nothing
3eec5767 4362 } elsif ($opt =~ m/^net(\d+)$/) {
b3c2bdd1 4363 die "skip\n" if !$hotplug_features->{network};
3eec5767 4364 vm_deviceunplug($vmid, $conf, $opt);
74479ee9 4365 } elsif (is_valid_drivename($opt)) {
b3c2bdd1 4366 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
19120f99 4367 vm_deviceunplug($vmid, $conf, $opt);
3dc38fbb 4368 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4d3f29ed
AD
4369 } elsif ($opt =~ m/^memory$/) {
4370 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4371 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
c8effec3
AD
4372 } elsif ($opt eq 'cpuunits') {
4373 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
58be00f1
AD
4374 } elsif ($opt eq 'cpulimit') {
4375 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
3d7389fe 4376 } else {
e56beeda 4377 die "skip\n";
3d7389fe 4378 }
3a11fadb
DM
4379 };
4380 if (my $err = $@) {
e56beeda
DM
4381 &$add_error($opt, $err) if $err ne "skip\n";
4382 } else {
3a11fadb 4383 delete $conf->{$opt};
98bc3aeb 4384 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
3d7389fe 4385 }
3d7389fe
DM
4386 }
4387
e5a66e48 4388 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
9ed7a77c 4389 $apply_pending_cloudinit = sub {
e5a66e48
WB
4390 return if $apply_pending_cloudinit_done; # once is enough
4391 $apply_pending_cloudinit_done = 1; # once is enough
4392
9ed7a77c 4393 my ($key, $value) = @_;
9ed7a77c
WB
4394
4395 my @cloudinit_opts = keys %$confdesc_cloudinit;
4396 foreach my $opt (keys %{$conf->{pending}}) {
4397 next if !grep { $_ eq $opt } @cloudinit_opts;
4398 $conf->{$opt} = delete $conf->{pending}->{$opt};
4399 }
4400
4401 my $new_conf = { %$conf };
4402 $new_conf->{$key} = $value;
4403 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4404 };
4405
3d7389fe 4406 foreach my $opt (keys %{$conf->{pending}}) {
3a11fadb 4407 next if $selection && !$selection->{$opt};
3d7389fe 4408 my $value = $conf->{pending}->{$opt};
3a11fadb 4409 eval {
51a6f637
AD
4410 if ($opt eq 'hotplug') {
4411 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4412 } elsif ($opt eq 'tablet') {
b3c2bdd1 4413 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4414 if ($value == 1) {
d559309f
WB
4415 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4416 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4417 if $arch eq 'aarch64';
3a11fadb 4418 } elsif ($value == 0) {
d559309f
WB
4419 vm_deviceunplug($vmid, $conf, 'tablet');
4420 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4421 }
4eb68604 4422 } elsif ($opt =~ m/^usb\d+$/) {
f745762b
DC
4423 die "skip\n";
4424 # since we cannot reliably hot unplug usb devices
4425 # we are disabling it
4eb68604
DC
4426 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4427 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4428 die "skip\n" if !$d;
d559309f 4429 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
8edc9c08 4430 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4431 die "skip\n" if !$hotplug_features->{cpu};
3a11fadb
DM
4432 qemu_cpu_hotplug($vmid, $conf, $value);
4433 } elsif ($opt eq 'balloon') {
81d95ae1 4434 # enable/disable balloning device is not hotpluggable
8fe689e7 4435 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
a1b7d579 4436 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
81d95ae1
DM
4437 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4438
3a11fadb 4439 # allow manual ballooning if shares is set to zero
4cc1efa6 4440 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
9c2f7069 4441 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
0a13e08e 4442 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
9c2f7069 4443 }
a1b7d579 4444 } elsif ($opt =~ m/^net(\d+)$/) {
3eec5767 4445 # some changes can be done without hotplug
a1b7d579 4446 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
d559309f 4447 $vmid, $opt, $value, $arch, $machine_type);
74479ee9 4448 } elsif (is_valid_drivename($opt)) {
7a4bdb36 4449 die "skip\n" if $opt eq 'efidisk0';
a05cff86 4450 # some changes can be done without hotplug
9ed7a77c
WB
4451 my $drive = parse_drive($opt, $value);
4452 if (drive_is_cloudinit($drive)) {
4453 &$apply_pending_cloudinit($opt, $value);
4454 }
b3c2bdd1 4455 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
9e7bce2c 4456 $vmid, $opt, $value, $arch, $machine_type);
4d3f29ed
AD
4457 } elsif ($opt =~ m/^memory$/) { #dimms
4458 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4459 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
c8effec3
AD
4460 } elsif ($opt eq 'cpuunits') {
4461 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
58be00f1 4462 } elsif ($opt eq 'cpulimit') {
c6f773b8 4463 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
58be00f1 4464 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
3a11fadb 4465 } else {
e56beeda 4466 die "skip\n"; # skip non-hot-pluggable options
3d7389fe 4467 }
3a11fadb
DM
4468 };
4469 if (my $err = $@) {
e56beeda
DM
4470 &$add_error($opt, $err) if $err ne "skip\n";
4471 } else {
3a11fadb
DM
4472 $conf->{$opt} = $value;
4473 delete $conf->{pending}->{$opt};
3d7389fe 4474 }
3d7389fe 4475 }
4df15a03
OB
4476
4477 PVE::QemuConfig->write_config($vmid, $conf);
c427973b 4478}
055d554d 4479
3dc38fbb
WB
4480sub try_deallocate_drive {
4481 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4482
4483 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4484 my $volid = $drive->{file};
4485 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4486 my $sid = PVE::Storage::parse_volume_id($volid);
4487 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
cee01bcb
WB
4488
4489 # check if the disk is really unused
cee01bcb 4490 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
e0fd2b2f 4491 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
cee01bcb 4492 PVE::Storage::vdisk_free($storecfg, $volid);
3dc38fbb 4493 return 1;
40b977f3
WL
4494 } else {
4495 # If vm is not owner of this disk remove from config
4496 return 1;
3dc38fbb
WB
4497 }
4498 }
4499
4500 return undef;
4501}
4502
4503sub vmconfig_delete_or_detach_drive {
4504 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4505
4506 my $drive = parse_drive($opt, $conf->{$opt});
4507
4508 my $rpcenv = PVE::RPCEnvironment::get();
4509 my $authuser = $rpcenv->get_user();
4510
4511 if ($force) {
4512 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
4513 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4514 } else {
4515 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4516 }
4517}
4518
98bc3aeb
OB
4519
4520
055d554d 4521sub vmconfig_apply_pending {
eb5e482d
OB
4522 my ($vmid, $conf, $storecfg, $errors) = @_;
4523
4524 my $add_apply_error = sub {
4525 my ($opt, $msg) = @_;
4526 my $err_msg = "unable to apply pending change $opt : $msg";
4527 $errors->{$opt} = $err_msg;
4528 warn $err_msg;
4529 };
c427973b
DM
4530
4531 # cold plug
055d554d 4532
98bc3aeb 4533 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 4534 foreach my $opt (sort keys %$pending_delete_hash) {
fb4d1ba2 4535 my $force = $pending_delete_hash->{$opt}->{force};
eb5e482d 4536 eval {
3d48b95a
OB
4537 if ($opt =~ m/^unused/) {
4538 die "internal error";
4539 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
eb5e482d 4540 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
eb5e482d
OB
4541 }
4542 };
4543 if (my $err = $@) {
4544 $add_apply_error->($opt, $err);
055d554d 4545 } else {
98bc3aeb 4546 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
055d554d 4547 delete $conf->{$opt};
055d554d
DM
4548 }
4549 }
4550
3d48b95a 4551 PVE::QemuConfig->cleanup_pending($conf);
055d554d
DM
4552
4553 foreach my $opt (keys %{$conf->{pending}}) { # add/change
3d48b95a 4554 next if $opt eq 'delete'; # just to be sure
eb5e482d 4555 eval {
3d48b95a 4556 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
eb5e482d 4557 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
eb5e482d
OB
4558 }
4559 };
4560 if (my $err = $@) {
4561 $add_apply_error->($opt, $err);
055d554d 4562 } else {
eb5e482d 4563 $conf->{$opt} = delete $conf->{pending}->{$opt};
055d554d 4564 }
055d554d 4565 }
3d48b95a
OB
4566
4567 # write all changes at once to avoid unnecessary i/o
4568 PVE::QemuConfig->write_config($vmid, $conf);
055d554d
DM
4569}
4570
3eec5767 4571sub vmconfig_update_net {
d559309f 4572 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
3eec5767
DM
4573
4574 my $newnet = parse_net($value);
4575
4576 if ($conf->{$opt}) {
4577 my $oldnet = parse_net($conf->{$opt});
4578
0f1af9e7
OB
4579 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4580 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4581 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
3eec5767
DM
4582 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4583
4584 # for non online change, we try to hot-unplug
7196b757 4585 die "skip\n" if !$hotplug;
3eec5767
DM
4586 vm_deviceunplug($vmid, $conf, $opt);
4587 } else {
4588
4589 die "internal error" if $opt !~ m/net(\d+)/;
4590 my $iface = "tap${vmid}i$1";
a1b7d579 4591
0f1af9e7
OB
4592 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4593 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4594 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4595 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
3eec5767 4596 PVE::Network::tap_unplug($iface);
28e129cc
AD
4597
4598 if ($have_sdn) {
4599 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4600 } else {
4601 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4602 }
0f1af9e7 4603 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4f4fbeb0
WB
4604 # Rate can be applied on its own but any change above needs to
4605 # include the rate in tap_plug since OVS resets everything.
4606 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
3eec5767 4607 }
38c590d9 4608
0f1af9e7 4609 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
25088687
DM
4610 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4611 }
4612
38c590d9 4613 return 1;
3eec5767
DM
4614 }
4615 }
a1b7d579 4616
7196b757 4617 if ($hotplug) {
d559309f 4618 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
38c590d9
DM
4619 } else {
4620 die "skip\n";
4621 }
3eec5767
DM
4622}
4623
a05cff86 4624sub vmconfig_update_disk {
9e7bce2c 4625 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
a05cff86
DM
4626
4627 my $drive = parse_drive($opt, $value);
4628
4629 if ($conf->{$opt}) {
4630
4631 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4632
4633 my $media = $drive->{media} || 'disk';
4634 my $oldmedia = $old_drive->{media} || 'disk';
4635 die "unable to change media type\n" if $media ne $oldmedia;
4636
4637 if (!drive_is_cdrom($old_drive)) {
4638
a1b7d579 4639 if ($drive->{file} ne $old_drive->{file}) {
a05cff86 4640
7196b757 4641 die "skip\n" if !$hotplug;
a05cff86
DM
4642
4643 # unplug and register as unused
4644 vm_deviceunplug($vmid, $conf, $opt);
4645 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
a1b7d579 4646
a05cff86
DM
4647 } else {
4648 # update existing disk
4649
4650 # skip non hotpluggable value
0f1af9e7
OB
4651 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4652 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4653 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4654 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
4655 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
a05cff86
DM
4656 die "skip\n";
4657 }
4658
4659 # apply throttle
0f1af9e7
OB
4660 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4661 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4662 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4663 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4664 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4665 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4666 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4667 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4668 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4669 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4670 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4671 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4672 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4673 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4674 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4675 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4676 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4677 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
a1b7d579 4678
a05cff86
DM
4679 qemu_block_set_io_throttle($vmid,"drive-$opt",
4680 ($drive->{mbps} || 0)*1024*1024,
4681 ($drive->{mbps_rd} || 0)*1024*1024,
4682 ($drive->{mbps_wr} || 0)*1024*1024,
4683 $drive->{iops} || 0,
4684 $drive->{iops_rd} || 0,
4685 $drive->{iops_wr} || 0,
4686 ($drive->{mbps_max} || 0)*1024*1024,
4687 ($drive->{mbps_rd_max} || 0)*1024*1024,
4688 ($drive->{mbps_wr_max} || 0)*1024*1024,
4689 $drive->{iops_max} || 0,
4690 $drive->{iops_rd_max} || 0,
9196a8ec
WB
4691 $drive->{iops_wr_max} || 0,
4692 $drive->{bps_max_length} || 1,
4693 $drive->{bps_rd_max_length} || 1,
4694 $drive->{bps_wr_max_length} || 1,
4695 $drive->{iops_max_length} || 1,
4696 $drive->{iops_rd_max_length} || 1,
4697 $drive->{iops_wr_max_length} || 1);
a05cff86
DM
4698
4699 }
a1b7d579 4700
a05cff86
DM
4701 return 1;
4702 }
4de1bb25
DM
4703
4704 } else { # cdrom
a1b7d579 4705
4de1bb25 4706 if ($drive->{file} eq 'none') {
922869f2 4707 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
2d9ddec5
WB
4708 if (drive_is_cloudinit($old_drive)) {
4709 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4710 }
4de1bb25
DM
4711 } else {
4712 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
ce9fce79
SR
4713
4714 # force eject if locked
922869f2 4715 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
ce9fce79
SR
4716
4717 if ($path) {
4718 mon_cmd($vmid, "blockdev-change-medium",
922869f2 4719 id => "$opt", filename => "$path");
ce9fce79 4720 }
4de1bb25 4721 }
a1b7d579 4722
34758d66 4723 return 1;
a05cff86
DM
4724 }
4725 }
4726 }
4727
a1b7d579 4728 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4de1bb25 4729 # hotplug new disks
f7b4356f 4730 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
d559309f 4731 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
a05cff86
DM
4732}
4733
13cfe3b7 4734# called in locked context by incoming migration
ba5396b5
FG
4735sub vm_migrate_get_nbd_disks {
4736 my ($storecfg, $conf, $replicated_volumes) = @_;
13cfe3b7
FG
4737
4738 my $local_volumes = {};
4739 foreach_drive($conf, sub {
4740 my ($ds, $drive) = @_;
4741
4742 return if drive_is_cdrom($drive);
4743
4744 my $volid = $drive->{file};
4745
4746 return if !$volid;
4747
4748 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4749
4750 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4751 return if $scfg->{shared};
ba5396b5
FG
4752
4753 # replicated disks re-use existing state via bitmap
4754 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
4755 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
13cfe3b7 4756 });
ba5396b5
FG
4757 return $local_volumes;
4758}
4759
4760# called in locked context by incoming migration
4761sub vm_migrate_alloc_nbd_disks {
4762 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
13cfe3b7
FG
4763
4764 my $format = undef;
4765
4766 my $nbd = {};
ba5396b5
FG
4767 foreach my $opt (sort keys %$source_volumes) {
4768 my ($volid, $storeid, $volname, $drive, $use_existing) = @{$source_volumes->{$opt}};
4769
4770 if ($use_existing) {
4771 $nbd->{$opt}->{drivestr} = print_drive($drive);
4772 $nbd->{$opt}->{volid} = $volid;
4773 $nbd->{$opt}->{replicated} = 1;
13cfe3b7
FG
4774 next;
4775 }
13cfe3b7
FG
4776
4777 # If a remote storage is specified and the format of the original
4778 # volume is not available there, fall back to the default format.
4779 # Otherwise use the same format as the original.
bf8fc5a3
FG
4780 if (!$storagemap->{identity}) {
4781 $storeid = map_storage($storagemap, $storeid);
13cfe3b7
FG
4782 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4783 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4784 my $fileFormat = qemu_img_format($scfg, $volname);
4785 $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
4786 } else {
4787 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4788 $format = qemu_img_format($scfg, $volname);
4789 }
4790
4791 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4792 my $newdrive = $drive;
4793 $newdrive->{format} = $format;
4794 $newdrive->{file} = $newvolid;
4795 my $drivestr = print_drive($newdrive);
ba5396b5
FG
4796 $nbd->{$opt}->{drivestr} = $drivestr;
4797 $nbd->{$opt}->{volid} = $newvolid;
13cfe3b7
FG
4798 }
4799
4800 return $nbd;
4801}
4802
4803# see vm_start_nolock for parameters, additionally:
4804# migrate_opts:
bf8fc5a3 4805# storagemap = parsed storage map for allocating NBD disks
3898a563
FG
4806sub vm_start {
4807 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
4808
84da8217 4809 return PVE::QemuConfig->lock_config($vmid, sub {
3898a563
FG
4810 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
4811
4812 die "you can't start a vm if it's a template\n" if PVE::QemuConfig->is_template($conf);
4813
4814 $params->{resume} = PVE::QemuConfig->has_lock($conf, 'suspended');
4815
4816 PVE::QemuConfig->check_lock($conf)
4817 if !($params->{skiplock} || $params->{resume});
4818
4819 die "VM $vmid already running\n" if check_running($vmid, undef, $migrate_opts->{migratedfrom});
4820
ba5396b5
FG
4821 if (my $storagemap = $migrate_opts->{storagemap}) {
4822 my $replicated = $migrate_opts->{replicated_volumes};
4823 my $disks = vm_migrate_get_nbd_disks($storecfg, $conf, $replicated);
4824 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $disks, $storagemap);
4825
4826 foreach my $opt (keys %{$migrate_opts->{nbd}}) {
4827 $conf->{$opt} = $migrate_opts->{nbd}->{$opt}->{drivestr};
4828 }
4829 }
13cfe3b7 4830
84da8217 4831 return vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
3898a563
FG
4832 });
4833}
4834
4835
0c498cca
FG
4836# params:
4837# statefile => 'tcp', 'unix' for migration or path/volid for RAM state
4838# skiplock => 0/1, skip checking for config lock
4839# forcemachine => to force Qemu machine (rollback/migration)
4840# timeout => in seconds
4841# paused => start VM in paused state (backup)
3898a563 4842# resume => resume from hibernation
0c498cca 4843# migrate_opts:
ba5396b5 4844# nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
0c498cca
FG
4845# migratedfrom => source node
4846# spice_ticket => used for spice migration, passed via tunnel/stdin
4847# network => CIDR of migration network
4848# type => secure/insecure - tunnel over encrypted connection or plain-text
0c498cca
FG
4849# nbd_proto_version => int, 0 for TCP, 1 for UNIX
4850# replicated_volumes = which volids should be re-used with bitmaps for nbd migration
3898a563
FG
4851sub vm_start_nolock {
4852 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
1e3baf05 4853
3898a563
FG
4854 my $statefile = $params->{statefile};
4855 my $resume = $params->{resume};
3dcb98d5 4856
3898a563
FG
4857 my $migratedfrom = $migrate_opts->{migratedfrom};
4858 my $migration_type = $migrate_opts->{type};
7ceade4c 4859
84da8217
FG
4860 my $res = {};
4861
3898a563
FG
4862 # clean up leftover reboot request files
4863 eval { clear_reboot_request($vmid); };
4864 warn $@ if $@;
1e3baf05 4865
3898a563
FG
4866 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4867 vmconfig_apply_pending($vmid, $conf, $storecfg);
4868 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4869 }
64457ed4 4870
3898a563 4871 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
055d554d 4872
3898a563 4873 my $defaults = load_defaults();
0c9a7596 4874
3898a563
FG
4875 # set environment variable useful inside network script
4876 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
6c47d546 4877
3898a563 4878 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 1);
9e784b11 4879
3898a563
FG
4880 my $forcemachine = $params->{forcemachine};
4881 if ($resume) {
4882 # enforce machine type on suspended vm to ensure HW compatibility
4883 $forcemachine = $conf->{runningmachine};
4884 print "Resuming suspended VM\n";
4885 }
7ceade4c 4886
3898a563 4887 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
6c47d546 4888
3898a563
FG
4889 my $migration_ip;
4890 my $get_migration_ip = sub {
4891 my ($nodename) = @_;
b24e1ac2 4892
3898a563 4893 return $migration_ip if defined($migration_ip);
b24e1ac2 4894
3898a563 4895 my $cidr = $migrate_opts->{network};
0c498cca 4896
3898a563
FG
4897 if (!defined($cidr)) {
4898 my $dc_conf = PVE::Cluster::cfs_read_file('datacenter.cfg');
4899 $cidr = $dc_conf->{migration}->{network};
4900 }
b24e1ac2 4901
3898a563
FG
4902 if (defined($cidr)) {
4903 my $ips = PVE::Network::get_local_ip_from_cidr($cidr);
b24e1ac2 4904
3898a563
FG
4905 die "could not get IP: no address configured on local " .
4906 "node for network '$cidr'\n" if scalar(@$ips) == 0;
b24e1ac2 4907
3898a563
FG
4908 die "could not get IP: multiple addresses configured on local " .
4909 "node for network '$cidr'\n" if scalar(@$ips) > 1;
b24e1ac2 4910
3898a563
FG
4911 $migration_ip = @$ips[0];
4912 }
b24e1ac2 4913
3898a563
FG
4914 $migration_ip = PVE::Cluster::remote_node_ip($nodename, 1)
4915 if !defined($migration_ip);
b24e1ac2 4916
3898a563
FG
4917 return $migration_ip;
4918 };
b24e1ac2 4919
3898a563
FG
4920 my $migrate_uri;
4921 if ($statefile) {
4922 if ($statefile eq 'tcp') {
4923 my $localip = "localhost";
4924 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
4925 my $nodename = nodename();
2de2d6f7 4926
3898a563
FG
4927 if (!defined($migration_type)) {
4928 if (defined($datacenterconf->{migration}->{type})) {
4929 $migration_type = $datacenterconf->{migration}->{type};
4930 } else {
4931 $migration_type = 'secure';
b7a5a225 4932 }
3898a563 4933 }
b7a5a225 4934
3898a563
FG
4935 if ($migration_type eq 'insecure') {
4936 $localip = $get_migration_ip->($nodename);
4937 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4938 }
2de2d6f7 4939
3898a563
FG
4940 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4941 my $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4942 $migrate_uri = "tcp:${localip}:${migrate_port}";
4943 push @$cmd, '-incoming', $migrate_uri;
4944 push @$cmd, '-S';
1c9d54bf 4945
3898a563
FG
4946 } elsif ($statefile eq 'unix') {
4947 # should be default for secure migrations as a ssh TCP forward
4948 # tunnel is not deterministic reliable ready and fails regurarly
4949 # to set up in time, so use UNIX socket forwards
4950 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4951 unlink $socket_addr;
54323eed 4952
3898a563 4953 $migrate_uri = "unix:$socket_addr";
1c9d54bf 4954
3898a563
FG
4955 push @$cmd, '-incoming', $migrate_uri;
4956 push @$cmd, '-S';
1c9d54bf 4957
3898a563
FG
4958 } elsif (-e $statefile) {
4959 push @$cmd, '-loadstate', $statefile;
4960 } else {
4961 my $statepath = PVE::Storage::path($storecfg, $statefile);
4962 push @$vollist, $statefile;
4963 push @$cmd, '-loadstate', $statepath;
4964 }
4965 } elsif ($params->{paused}) {
4966 push @$cmd, '-S';
4967 }
4968
4969 # host pci devices
4970 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4971 my $d = parse_hostpci($conf->{"hostpci$i"});
4972 next if !$d;
4973 my $pcidevices = $d->{pciid};
4974 foreach my $pcidevice (@$pcidevices) {
4975 my $pciid = $pcidevice->{id};
4976
4977 my $info = PVE::SysFSTools::pci_device_info("$pciid");
4978 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
4979 die "no pci device info for device '$pciid'\n" if !$info;
4980
4981 if ($d->{mdev}) {
4982 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
4983 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5c1d42b7 4984 } else {
3898a563
FG
4985 die "can't unbind/bind pci group to vfio '$pciid'\n"
4986 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
4987 die "can't reset pci device '$pciid'\n"
4988 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
1e3baf05 4989 }
3898a563
FG
4990 }
4991 }
1e3baf05 4992
3898a563 4993 PVE::Storage::activate_volumes($storecfg, $vollist);
1e3baf05 4994
3898a563
FG
4995 eval {
4996 run_command(['/bin/systemctl', 'stop', "$vmid.scope"],
4997 outfunc => sub {}, errfunc => sub {});
4998 };
4999 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5000 # timeout should be more than enough here...
5001 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
5002
5003 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5004 : $defaults->{cpuunits};
5005
5006 my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $resume);
5007 my %run_params = (
5008 timeout => $statefile ? undef : $start_timeout,
5009 umask => 0077,
5010 noerr => 1,
5011 );
1e3baf05 5012
3898a563
FG
5013 # when migrating, prefix QEMU output so other side can pick up any
5014 # errors that might occur and show the user
5015 if ($migratedfrom) {
5016 $run_params{quiet} = 1;
5017 $run_params{logfunc} = sub { print "QEMU: $_[0]\n" };
5018 }
8bf30c2a 5019
3898a563
FG
5020 my %properties = (
5021 Slice => 'qemu.slice',
5022 KillMode => 'none',
5023 CPUShares => $cpuunits
5024 );
7023f3ea 5025
3898a563
FG
5026 if (my $cpulimit = $conf->{cpulimit}) {
5027 $properties{CPUQuota} = int($cpulimit * 100);
5028 }
5029 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
7023f3ea 5030
3898a563
FG
5031 my $run_qemu = sub {
5032 PVE::Tools::run_fork sub {
5033 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
6e0216d8 5034
3898a563
FG
5035 my $exitcode = run_command($cmd, %run_params);
5036 die "QEMU exited with code $exitcode\n" if $exitcode;
503308ed 5037 };
3898a563 5038 };
503308ed 5039
3898a563 5040 if ($conf->{hugepages}) {
7023f3ea 5041
3898a563
FG
5042 my $code = sub {
5043 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5044 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
7023f3ea 5045
3898a563
FG
5046 PVE::QemuServer::Memory::hugepages_mount();
5047 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
7023f3ea 5048
503308ed 5049 eval { $run_qemu->() };
3898a563
FG
5050 if (my $err = $@) {
5051 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5052 die $err;
5053 }
77cde36b 5054
3898a563
FG
5055 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5056 };
5057 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
1e3baf05 5058
3898a563
FG
5059 } else {
5060 eval { $run_qemu->() };
5061 }
afdb31d5 5062
3898a563
FG
5063 if (my $err = $@) {
5064 # deactivate volumes if start fails
5065 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5066 die "start failed: $err";
5067 }
62de2cbd 5068
3898a563 5069 print "migration listens on $migrate_uri\n" if $migrate_uri;
84da8217 5070 $res->{migrate_uri} = $migrate_uri;
eb8cddb5 5071
3898a563
FG
5072 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
5073 eval { mon_cmd($vmid, "cont"); };
5074 warn $@ if $@;
5075 }
2189246c 5076
3898a563 5077 #start nbd server for storage migration
13cfe3b7 5078 if (my $nbd = $migrate_opts->{nbd}) {
3898a563 5079 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version} // 0;
2189246c 5080
3898a563
FG
5081 my $migrate_storage_uri;
5082 # nbd_protocol_version > 0 for unix socket support
5083 if ($nbd_protocol_version > 0 && $migration_type eq 'secure') {
5084 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5085 mon_cmd($vmid, "nbd-server-start", addr => { type => 'unix', data => { path => $socket_path } } );
5086 $migrate_storage_uri = "nbd:unix:$socket_path";
5087 } else {
5088 my $nodename = nodename();
5089 my $localip = $get_migration_ip->($nodename);
5090 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5091 my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
5092
5093 mon_cmd($vmid, "nbd-server-start", addr => { type => 'inet', data => { host => "${localip}", port => "${storage_migrate_port}" } } );
5094 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5095 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
2189246c
AD
5096 }
5097
84da8217
FG
5098 $res->{migrate_storage_uri} = $migrate_storage_uri;
5099
13cfe3b7 5100 foreach my $opt (sort keys %$nbd) {
ba5396b5
FG
5101 my $drivestr = $nbd->{$opt}->{drivestr};
5102 my $volid = $nbd->{$opt}->{volid};
3898a563 5103 mon_cmd($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
84da8217
FG
5104 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
5105 print "storage migration listens on $nbd_uri volume:$drivestr\n";
ba5396b5
FG
5106 print "re-using replicated volume: $opt - $volid\n"
5107 if $nbd->{$opt}->{replicated};
84da8217
FG
5108
5109 $res->{drives}->{$opt} = $nbd->{$opt};
5110 $res->{drives}->{$opt}->{nbd_uri} = $nbd_uri;
3898a563
FG
5111 }
5112 }
a89fded1 5113
3898a563
FG
5114 if ($migratedfrom) {
5115 eval {
5116 set_migration_caps($vmid);
5117 };
5118 warn $@ if $@;
5119
5120 if ($spice_port) {
5121 print "spice listens on port $spice_port\n";
84da8217 5122 $res->{spice_port} = $spice_port;
3898a563
FG
5123 if ($migrate_opts->{spice_ticket}) {
5124 mon_cmd($vmid, "set_password", protocol => 'spice', password => $migrate_opts->{spice_ticket});
5125 mon_cmd($vmid, "expire_password", protocol => 'spice', time => "+30");
95a4b4a9 5126 }
3898a563 5127 }
95a4b4a9 5128
3898a563
FG
5129 } else {
5130 mon_cmd($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5131 if !$statefile && $conf->{balloon};
25088687 5132
3898a563
FG
5133 foreach my $opt (keys %$conf) {
5134 next if $opt !~ m/^net\d+$/;
5135 my $nicconf = parse_net($conf->{$opt});
5136 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
e18b0b99 5137 }
3898a563 5138 }
a1b7d579 5139
3898a563
FG
5140 mon_cmd($vmid, 'qom-set',
5141 path => "machine/peripheral/balloon0",
5142 property => "guest-stats-polling-interval",
5143 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
eb065317 5144
3898a563
FG
5145 if ($resume) {
5146 print "Resumed VM, removing state\n";
5147 if (my $vmstate = $conf->{vmstate}) {
5148 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5149 PVE::Storage::vdisk_free($storecfg, $vmstate);
7ceade4c 5150 }
3898a563
FG
5151 delete $conf->@{qw(lock vmstate runningmachine)};
5152 PVE::QemuConfig->write_config($vmid, $conf);
5153 }
7ceade4c 5154
3898a563 5155 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start');
84da8217
FG
5156
5157 return $res;
1e3baf05
DM
5158}
5159
1e3baf05 5160sub vm_commandline {
b14477e7 5161 my ($storecfg, $vmid, $snapname) = @_;
1e3baf05 5162
ffda963f 5163 my $conf = PVE::QemuConfig->load_config($vmid);
092868c4 5164 my $forcemachine;
1e3baf05 5165
b14477e7
RV
5166 if ($snapname) {
5167 my $snapshot = $conf->{snapshots}->{$snapname};
87d92707
TL
5168 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5169
092868c4
SR
5170 # check for a 'runningmachine' in snapshot
5171 $forcemachine = $snapshot->{runningmachine} if $snapshot->{runningmachine};
5172
87d92707 5173 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
b14477e7 5174
b14477e7
RV
5175 $conf = $snapshot;
5176 }
5177
1e3baf05
DM
5178 my $defaults = load_defaults();
5179
092868c4 5180 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
1e3baf05 5181
5930c1ff 5182 return PVE::Tools::cmd2string($cmd);
1e3baf05
DM
5183}
5184
5185sub vm_reset {
5186 my ($vmid, $skiplock) = @_;
5187
ffda963f 5188 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5189
ffda963f 5190 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5191
ffda963f 5192 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 5193
0a13e08e 5194 mon_cmd($vmid, "system_reset");
ff1a2432
DM
5195 });
5196}
5197
5198sub get_vm_volumes {
5199 my ($conf) = @_;
1e3baf05 5200
ff1a2432 5201 my $vollist = [];
d5769dc2 5202 foreach_volid($conf, sub {
392f8b5d 5203 my ($volid, $attr) = @_;
ff1a2432 5204
d5769dc2 5205 return if $volid =~ m|^/|;
ff1a2432 5206
d5769dc2
DM
5207 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5208 return if !$sid;
ff1a2432
DM
5209
5210 push @$vollist, $volid;
1e3baf05 5211 });
ff1a2432
DM
5212
5213 return $vollist;
5214}
5215
5216sub vm_stop_cleanup {
70b04821 5217 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
ff1a2432 5218
745fed70 5219 eval {
ff1a2432 5220
254575e9
DM
5221 if (!$keepActive) {
5222 my $vollist = get_vm_volumes($conf);
5223 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5224 }
a1b7d579 5225
ab6a046f 5226 foreach my $ext (qw(mon qmp pid vnc qga)) {
961bfcb2
DM
5227 unlink "/var/run/qemu-server/${vmid}.$ext";
5228 }
a1b7d579 5229
6dbcb073
DC
5230 if ($conf->{ivshmem}) {
5231 my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
4c5a6a24
TL
5232 # just delete it for now, VMs which have this already open do not
5233 # are affected, but new VMs will get a separated one. If this
5234 # becomes an issue we either add some sort of ref-counting or just
5235 # add a "don't delete on stop" flag to the ivshmem format.
6dbcb073
DC
5236 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name} // $vmid);
5237 }
5238
6ab45bd7
DC
5239 foreach my $key (keys %$conf) {
5240 next if $key !~ m/^hostpci(\d+)$/;
5241 my $hostpciindex = $1;
5242 my $d = parse_hostpci($conf->{$key});
5243 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $hostpciindex);
5244
5245 foreach my $pci (@{$d->{pciid}}) {
2fd24788 5246 my $pciid = $pci->{id};
6ab45bd7
DC
5247 PVE::SysFSTools::pci_cleanup_mdev_device($pciid, $uuid);
5248 }
5249 }
5250
70b04821 5251 vmconfig_apply_pending($vmid, $conf, $storecfg) if $apply_pending_changes;
745fed70
DM
5252 };
5253 warn $@ if $@; # avoid errors - just warn
1e3baf05
DM
5254}
5255
575d19da
DC
5256# call only in locked context
5257sub _do_vm_stop {
5258 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
9269013a 5259
575d19da
DC
5260 my $pid = check_running($vmid, $nocheck);
5261 return if !$pid;
1e3baf05 5262
575d19da
DC
5263 my $conf;
5264 if (!$nocheck) {
5265 $conf = PVE::QemuConfig->load_config($vmid);
5266 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5267 if (!defined($timeout) && $shutdown && $conf->{startup}) {
5268 my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup});
5269 $timeout = $opts->{down} if $opts->{down};
e6c3b671 5270 }
575d19da
DC
5271 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-stop');
5272 }
19672434 5273
575d19da
DC
5274 eval {
5275 if ($shutdown) {
5276 if (defined($conf) && parse_guest_agent($conf)->{enabled}) {
0a13e08e 5277 mon_cmd($vmid, "guest-shutdown", timeout => $timeout);
9269013a 5278 } else {
0a13e08e 5279 mon_cmd($vmid, "system_powerdown");
1e3baf05
DM
5280 }
5281 } else {
0a13e08e 5282 mon_cmd($vmid, "quit");
1e3baf05 5283 }
575d19da
DC
5284 };
5285 my $err = $@;
1e3baf05 5286
575d19da
DC
5287 if (!$err) {
5288 $timeout = 60 if !defined($timeout);
1e3baf05
DM
5289
5290 my $count = 0;
e6c3b671 5291 while (($count < $timeout) && check_running($vmid, $nocheck)) {
1e3baf05
DM
5292 $count++;
5293 sleep 1;
5294 }
5295
5296 if ($count >= $timeout) {
575d19da
DC
5297 if ($force) {
5298 warn "VM still running - terminating now with SIGTERM\n";
5299 kill 15, $pid;
5300 } else {
5301 die "VM quit/powerdown failed - got timeout\n";
5302 }
5303 } else {
5304 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5305 return;
1e3baf05 5306 }
575d19da
DC
5307 } else {
5308 if ($force) {
5309 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5310 kill 15, $pid;
5311 } else {
5312 die "VM quit/powerdown failed\n";
5313 }
5314 }
5315
5316 # wait again
5317 $timeout = 10;
5318
5319 my $count = 0;
5320 while (($count < $timeout) && check_running($vmid, $nocheck)) {
5321 $count++;
5322 sleep 1;
5323 }
5324
5325 if ($count >= $timeout) {
5326 warn "VM still running - terminating now with SIGKILL\n";
5327 kill 9, $pid;
5328 sleep 1;
5329 }
1e3baf05 5330
575d19da
DC
5331 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5332}
5333
5334# Note: use $nocheck to skip tests if VM configuration file exists.
5335# We need that when migration VMs to other nodes (files already moved)
5336# Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5337sub vm_stop {
5338 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5339
5340 $force = 1 if !defined($force) && !$shutdown;
5341
5342 if ($migratedfrom){
5343 my $pid = check_running($vmid, $nocheck, $migratedfrom);
5344 kill 15, $pid if $pid;
5345 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5346 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 0);
5347 return;
5348 }
5349
5350 PVE::QemuConfig->lock_config($vmid, sub {
5351 _do_vm_stop($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
ff1a2432 5352 });
1e3baf05
DM
5353}
5354
165411f0
DC
5355sub vm_reboot {
5356 my ($vmid, $timeout) = @_;
5357
5358 PVE::QemuConfig->lock_config($vmid, sub {
66026117 5359 eval {
165411f0 5360
66026117
OB
5361 # only reboot if running, as qmeventd starts it again on a stop event
5362 return if !check_running($vmid);
165411f0 5363
66026117 5364 create_reboot_request($vmid);
165411f0 5365
66026117
OB
5366 my $storecfg = PVE::Storage::config();
5367 _do_vm_stop($storecfg, $vmid, undef, undef, $timeout, 1);
165411f0 5368
66026117
OB
5369 };
5370 if (my $err = $@) {
3c1c3fe6 5371 # avoid that the next normal shutdown will be confused for a reboot
66026117
OB
5372 clear_reboot_request($vmid);
5373 die $err;
5374 }
165411f0
DC
5375 });
5376}
5377
75c24bba 5378# note: if using the statestorage parameter, the caller has to check privileges
1e3baf05 5379sub vm_suspend {
48b4cdc2 5380 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
159719e5
DC
5381
5382 my $conf;
5383 my $path;
5384 my $storecfg;
5385 my $vmstate;
1e3baf05 5386
ffda963f 5387 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5388
159719e5 5389 $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5390
159719e5 5391 my $is_backing_up = PVE::QemuConfig->has_lock($conf, 'backup');
e79706d4 5392 PVE::QemuConfig->check_lock($conf)
159719e5
DC
5393 if !($skiplock || $is_backing_up);
5394
5395 die "cannot suspend to disk during backup\n"
5396 if $is_backing_up && $includestate;
bcb7c9cf 5397
159719e5
DC
5398 if ($includestate) {
5399 $conf->{lock} = 'suspending';
5400 my $date = strftime("%Y-%m-%d", localtime(time()));
5401 $storecfg = PVE::Storage::config();
75c24bba
DC
5402 if (!$statestorage) {
5403 $statestorage = find_vmstate_storage($conf, $storecfg);
5404 # check permissions for the storage
5405 my $rpcenv = PVE::RPCEnvironment::get();
5406 if ($rpcenv->{type} ne 'cli') {
5407 my $authuser = $rpcenv->get_user();
5408 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
5409 }
5410 }
5411
5412
48b4cdc2 5413 $vmstate = PVE::QemuConfig->__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
159719e5
DC
5414 $path = PVE::Storage::path($storecfg, $vmstate);
5415 PVE::QemuConfig->write_config($vmid, $conf);
5416 } else {
0a13e08e 5417 mon_cmd($vmid, "stop");
159719e5 5418 }
1e3baf05 5419 });
159719e5
DC
5420
5421 if ($includestate) {
5422 # save vm state
5423 PVE::Storage::activate_volumes($storecfg, [$vmstate]);
5424
5425 eval {
0a13e08e 5426 mon_cmd($vmid, "savevm-start", statefile => $path);
159719e5 5427 for(;;) {
0a13e08e 5428 my $state = mon_cmd($vmid, "query-savevm");
159719e5
DC
5429 if (!$state->{status}) {
5430 die "savevm not active\n";
5431 } elsif ($state->{status} eq 'active') {
5432 sleep(1);
5433 next;
5434 } elsif ($state->{status} eq 'completed') {
b0a9a385 5435 print "State saved, quitting\n";
159719e5
DC
5436 last;
5437 } elsif ($state->{status} eq 'failed' && $state->{error}) {
5438 die "query-savevm failed with error '$state->{error}'\n"
5439 } else {
5440 die "query-savevm returned status '$state->{status}'\n";
5441 }
5442 }
5443 };
5444 my $err = $@;
5445
5446 PVE::QemuConfig->lock_config($vmid, sub {
5447 $conf = PVE::QemuConfig->load_config($vmid);
5448 if ($err) {
5449 # cleanup, but leave suspending lock, to indicate something went wrong
5450 eval {
0a13e08e 5451 mon_cmd($vmid, "savevm-end");
159719e5
DC
5452 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5453 PVE::Storage::vdisk_free($storecfg, $vmstate);
5454 delete $conf->@{qw(vmstate runningmachine)};
5455 PVE::QemuConfig->write_config($vmid, $conf);
5456 };
5457 warn $@ if $@;
5458 die $err;
5459 }
5460
5461 die "lock changed unexpectedly\n"
5462 if !PVE::QemuConfig->has_lock($conf, 'suspending');
5463
0a13e08e 5464 mon_cmd($vmid, "quit");
159719e5
DC
5465 $conf->{lock} = 'suspended';
5466 PVE::QemuConfig->write_config($vmid, $conf);
5467 });
5468 }
1e3baf05
DM
5469}
5470
5471sub vm_resume {
289e0b85 5472 my ($vmid, $skiplock, $nocheck) = @_;
1e3baf05 5473
ffda963f 5474 PVE::QemuConfig->lock_config($vmid, sub {
0a13e08e 5475 my $res = mon_cmd($vmid, 'query-status');
c2786bed
DC
5476 my $resume_cmd = 'cont';
5477
5478 if ($res->{status} && $res->{status} eq 'suspended') {
5479 $resume_cmd = 'system_wakeup';
5480 }
5481
289e0b85 5482 if (!$nocheck) {
1e3baf05 5483
ffda963f 5484 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5485
e79706d4
FG
5486 PVE::QemuConfig->check_lock($conf)
5487 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
289e0b85 5488 }
3e24733b 5489
0a13e08e 5490 mon_cmd($vmid, $resume_cmd);
1e3baf05
DM
5491 });
5492}
5493
5fdbe4f0
DM
5494sub vm_sendkey {
5495 my ($vmid, $skiplock, $key) = @_;
1e3baf05 5496
ffda963f 5497 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5498
ffda963f 5499 my $conf = PVE::QemuConfig->load_config($vmid);
f5eb281a 5500
7b7c6d1b 5501 # there is no qmp command, so we use the human monitor command
0a13e08e 5502 my $res = PVE::QemuServer::Monitor::hmp_cmd($vmid, "sendkey $key");
d30820d6 5503 die $res if $res ne '';
1e3baf05
DM
5504 });
5505}
5506
3e16d5fc
DM
5507# vzdump restore implementaion
5508
ed221350 5509sub tar_archive_read_firstfile {
3e16d5fc 5510 my $archive = shift;
afdb31d5 5511
3e16d5fc
DM
5512 die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
5513
5514 # try to detect archive type first
387ba257 5515 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
3e16d5fc 5516 die "unable to open file '$archive'\n";
387ba257 5517 my $firstfile = <$fh>;
3e16d5fc 5518 kill 15, $pid;
387ba257 5519 close $fh;
3e16d5fc
DM
5520
5521 die "ERROR: archive contaions no data\n" if !$firstfile;
5522 chomp $firstfile;
5523
5524 return $firstfile;
5525}
5526
ed221350
DM
5527sub tar_restore_cleanup {
5528 my ($storecfg, $statfile) = @_;
3e16d5fc
DM
5529
5530 print STDERR "starting cleanup\n";
5531
5532 if (my $fd = IO::File->new($statfile, "r")) {
5533 while (defined(my $line = <$fd>)) {
5534 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5535 my $volid = $2;
5536 eval {
5537 if ($volid =~ m|^/|) {
5538 unlink $volid || die 'unlink failed\n';
5539 } else {
ed221350 5540 PVE::Storage::vdisk_free($storecfg, $volid);
3e16d5fc 5541 }
afdb31d5 5542 print STDERR "temporary volume '$volid' sucessfuly removed\n";
3e16d5fc
DM
5543 };
5544 print STDERR "unable to cleanup '$volid' - $@" if $@;
5545 } else {
5546 print STDERR "unable to parse line in statfile - $line";
afdb31d5 5547 }
3e16d5fc
DM
5548 }
5549 $fd->close();
5550 }
5551}
5552
d1e92cf6 5553sub restore_file_archive {
a0d1b1a2 5554 my ($archive, $vmid, $user, $opts) = @_;
3e16d5fc 5555
91bd6c90
DM
5556 my $format = $opts->{format};
5557 my $comp;
5558
5559 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5560 $format = 'tar' if !$format;
5561 $comp = 'gzip';
5562 } elsif ($archive =~ m/\.tar$/) {
5563 $format = 'tar' if !$format;
5564 } elsif ($archive =~ m/.tar.lzo$/) {
5565 $format = 'tar' if !$format;
5566 $comp = 'lzop';
5567 } elsif ($archive =~ m/\.vma$/) {
5568 $format = 'vma' if !$format;
5569 } elsif ($archive =~ m/\.vma\.gz$/) {
5570 $format = 'vma' if !$format;
5571 $comp = 'gzip';
5572 } elsif ($archive =~ m/\.vma\.lzo$/) {
5573 $format = 'vma' if !$format;
5574 $comp = 'lzop';
5575 } else {
5576 $format = 'vma' if !$format; # default
5577 }
5578
5579 # try to detect archive format
5580 if ($format eq 'tar') {
5581 return restore_tar_archive($archive, $vmid, $user, $opts);
5582 } else {
5583 return restore_vma_archive($archive, $vmid, $user, $opts, $comp);
5584 }
5585}
5586
d1e92cf6
DM
5587# hepler to remove disks that will not be used after restore
5588my $restore_cleanup_oldconf = sub {
5589 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
5590
5591 foreach_drive($oldconf, sub {
5592 my ($ds, $drive) = @_;
5593
5594 return if drive_is_cdrom($drive, 1);
5595
5596 my $volid = $drive->{file};
5597 return if !$volid || $volid =~ m|^/|;
5598
5599 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
5600 return if !$path || !$owner || ($owner != $vmid);
5601
5602 # Note: only delete disk we want to restore
5603 # other volumes will become unused
5604 if ($virtdev_hash->{$ds}) {
5605 eval { PVE::Storage::vdisk_free($storecfg, $volid); };
5606 if (my $err = $@) {
5607 warn $err;
5608 }
5609 }
5610 });
5611
5612 # delete vmstate files, after the restore we have no snapshots anymore
5613 foreach my $snapname (keys %{$oldconf->{snapshots}}) {
5614 my $snap = $oldconf->{snapshots}->{$snapname};
5615 if ($snap->{vmstate}) {
5616 eval { PVE::Storage::vdisk_free($storecfg, $snap->{vmstate}); };
5617 if (my $err = $@) {
5618 warn $err;
5619 }
5620 }
5621 }
5622};
5623
9f3d73bc
DM
5624# Helper to parse vzdump backup device hints
5625#
5626# $rpcenv: Environment, used to ckeck storage permissions
5627# $user: User ID, to check storage permissions
5628# $storecfg: Storage configuration
5629# $fh: the file handle for reading the configuration
5630# $devinfo: should contain device sizes for all backu-up'ed devices
5631# $options: backup options (pool, default storage)
5632#
5633# Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
5634my $parse_backup_hints = sub {
5635 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
d1e92cf6 5636
9f3d73bc 5637 my $virtdev_hash = {};
d1e92cf6 5638
9f3d73bc
DM
5639 while (defined(my $line = <$fh>)) {
5640 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5641 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5642 die "archive does not contain data for drive '$virtdev'\n"
5643 if !$devinfo->{$devname};
5644
5645 if (defined($options->{storage})) {
5646 $storeid = $options->{storage} || 'local';
5647 } elsif (!$storeid) {
5648 $storeid = 'local';
d1e92cf6 5649 }
9f3d73bc
DM
5650 $format = 'raw' if !$format;
5651 $devinfo->{$devname}->{devname} = $devname;
5652 $devinfo->{$devname}->{virtdev} = $virtdev;
5653 $devinfo->{$devname}->{format} = $format;
5654 $devinfo->{$devname}->{storeid} = $storeid;
5655
5656 # check permission on storage
5657 my $pool = $options->{pool}; # todo: do we need that?
5658 if ($user ne 'root@pam') {
5659 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
d1e92cf6 5660 }
d1e92cf6 5661
9f3d73bc
DM
5662 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5663 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
5664 my $virtdev = $1;
5665 my $drive = parse_drive($virtdev, $2);
5666 if (drive_is_cloudinit($drive)) {
5667 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
5668 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5669 my $format = qemu_img_format($scfg, $volname); # has 'raw' fallback
d1e92cf6 5670
9f3d73bc
DM
5671 $virtdev_hash->{$virtdev} = {
5672 format => $format,
5673 storeid => $options->{storage} // $storeid,
5674 size => PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE,
5675 is_cloudinit => 1,
5676 };
d1e92cf6 5677 }
9f3d73bc
DM
5678 }
5679 }
d1e92cf6 5680
9f3d73bc
DM
5681 return $virtdev_hash;
5682};
d1e92cf6 5683
9f3d73bc
DM
5684# Helper to allocate and activate all volumes required for a restore
5685#
5686# $storecfg: Storage configuration
5687# $virtdev_hash: as returned by parse_backup_hints()
5688#
5689# Returns: { $virtdev => $volid }
5690my $restore_allocate_devices = sub {
5691 my ($storecfg, $virtdev_hash, $vmid) = @_;
d1e92cf6 5692
9f3d73bc
DM
5693 my $map = {};
5694 foreach my $virtdev (sort keys %$virtdev_hash) {
5695 my $d = $virtdev_hash->{$virtdev};
5696 my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
5697 my $storeid = $d->{storeid};
5698 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
d1e92cf6 5699
9f3d73bc
DM
5700 # test if requested format is supported
5701 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5702 my $supported = grep { $_ eq $d->{format} } @$validFormats;
5703 $d->{format} = $defFormat if !$supported;
d1e92cf6 5704
9f3d73bc
DM
5705 my $name;
5706 if ($d->{is_cloudinit}) {
5707 $name = "vm-$vmid-cloudinit";
5708 $name .= ".$d->{format}" if $d->{format} ne 'raw';
d1e92cf6
DM
5709 }
5710
9f3d73bc 5711 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $d->{format}, $name, $alloc_size);
d1e92cf6 5712
9f3d73bc
DM
5713 print STDERR "new volume ID is '$volid'\n";
5714 $d->{volid} = $volid;
d1e92cf6 5715
9f3d73bc 5716 PVE::Storage::activate_volumes($storecfg, [$volid]);
d1e92cf6 5717
9f3d73bc 5718 $map->{$virtdev} = $volid;
d1e92cf6
DM
5719 }
5720
9f3d73bc
DM
5721 return $map;
5722};
d1e92cf6 5723
9f3d73bc 5724my $restore_update_config_line = sub {
91bd6c90
DM
5725 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5726
5727 return if $line =~ m/^\#qmdump\#/;
5728 return if $line =~ m/^\#vzdump\#/;
5729 return if $line =~ m/^lock:/;
5730 return if $line =~ m/^unused\d+:/;
5731 return if $line =~ m/^parent:/;
5732
b5b99790 5733 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
91bd6c90
DM
5734 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5735 # try to convert old 1.X settings
5736 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5737 foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
5738 my ($model, $macaddr) = split(/\=/, $devconfig);
b5b99790 5739 $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
91bd6c90
DM
5740 my $net = {
5741 model => $model,
5742 bridge => "vmbr$ind",
5743 macaddr => $macaddr,
5744 };
5745 my $netstr = print_net($net);
5746
5747 print $outfd "net$cookie->{netcount}: $netstr\n";
5748 $cookie->{netcount}++;
5749 }
5750 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5751 my ($id, $netstr) = ($1, $2);
5752 my $net = parse_net($netstr);
b5b99790 5753 $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
91bd6c90
DM
5754 $netstr = print_net($net);
5755 print $outfd "$id: $netstr\n";
6470743f 5756 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
91bd6c90 5757 my $virtdev = $1;
907ea891 5758 my $value = $3;
d9faf790
WB
5759 my $di = parse_drive($virtdev, $value);
5760 if (defined($di->{backup}) && !$di->{backup}) {
91bd6c90 5761 print $outfd "#$line";
c0f7406e 5762 } elsif ($map->{$virtdev}) {
8fd57431 5763 delete $di->{format}; # format can change on restore
91bd6c90 5764 $di->{file} = $map->{$virtdev};
71c58bb7 5765 $value = print_drive($di);
91bd6c90
DM
5766 print $outfd "$virtdev: $value\n";
5767 } else {
5768 print $outfd $line;
5769 }
1a0c2f03 5770 } elsif (($line =~ m/^vmgenid: (.*)/)) {
babecffe 5771 my $vmgenid = $1;
6ee499ff 5772 if ($vmgenid ne '0') {
1a0c2f03 5773 # always generate a new vmgenid if there was a valid one setup
6ee499ff
DC
5774 $vmgenid = generate_uuid();
5775 }
1a0c2f03 5776 print $outfd "vmgenid: $vmgenid\n";
19a5dd55
WL
5777 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5778 my ($uuid, $uuid_str);
5779 UUID::generate($uuid);
5780 UUID::unparse($uuid, $uuid_str);
5781 my $smbios1 = parse_smbios1($2);
5782 $smbios1->{uuid} = $uuid_str;
5783 print $outfd $1.print_smbios1($smbios1)."\n";
91bd6c90
DM
5784 } else {
5785 print $outfd $line;
5786 }
9f3d73bc
DM
5787};
5788
5789my $restore_deactivate_volumes = sub {
5790 my ($storecfg, $devinfo) = @_;
5791
5792 my $vollist = [];
5793 foreach my $devname (keys %$devinfo) {
5794 my $volid = $devinfo->{$devname}->{volid};
5795 push @$vollist, $volid if $volid;
5796 }
5797
5798 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5799};
5800
5801my $restore_destroy_volumes = sub {
5802 my ($storecfg, $devinfo) = @_;
5803
5804 foreach my $devname (keys %$devinfo) {
5805 my $volid = $devinfo->{$devname}->{volid};
5806 next if !$volid;
5807 eval {
5808 if ($volid =~ m|^/|) {
5809 unlink $volid || die 'unlink failed\n';
5810 } else {
5811 PVE::Storage::vdisk_free($storecfg, $volid);
5812 }
5813 print STDERR "temporary volume '$volid' sucessfuly removed\n";
5814 };
5815 print STDERR "unable to cleanup '$volid' - $@" if $@;
5816 }
5817};
91bd6c90
DM
5818
5819sub scan_volids {
5820 my ($cfg, $vmid) = @_;
5821
5822 my $info = PVE::Storage::vdisk_list($cfg, undef, $vmid);
5823
5824 my $volid_hash = {};
5825 foreach my $storeid (keys %$info) {
5826 foreach my $item (@{$info->{$storeid}}) {
5827 next if !($item->{volid} && $item->{size});
5996a936 5828 $item->{path} = PVE::Storage::path($cfg, $item->{volid});
91bd6c90
DM
5829 $volid_hash->{$item->{volid}} = $item;
5830 }
5831 }
5832
5833 return $volid_hash;
5834}
5835
68b108ee 5836sub update_disk_config {
91bd6c90 5837 my ($vmid, $conf, $volid_hash) = @_;
be190583 5838
91bd6c90 5839 my $changes;
53b81297 5840 my $prefix = "VM $vmid:";
91bd6c90 5841
c449137a
DC
5842 # used and unused disks
5843 my $referenced = {};
91bd6c90 5844
5996a936
DM
5845 # Note: it is allowed to define multiple storages with same path (alias), so
5846 # we need to check both 'volid' and real 'path' (two different volid can point
5847 # to the same path).
5848
c449137a 5849 my $referencedpath = {};
be190583 5850
91bd6c90 5851 # update size info
0c4fef3f 5852 PVE::QemuConfig->foreach_volume($conf, sub {
ca04977c 5853 my ($opt, $drive) = @_;
91bd6c90 5854
ca04977c
FE
5855 my $volid = $drive->{file};
5856 return if !$volid;
91bd6c90 5857
ca04977c
FE
5858 # mark volid as "in-use" for next step
5859 $referenced->{$volid} = 1;
5860 if ($volid_hash->{$volid} &&
5861 (my $path = $volid_hash->{$volid}->{path})) {
5862 $referencedpath->{$path} = 1;
91bd6c90 5863 }
ca04977c
FE
5864
5865 return if drive_is_cdrom($drive);
5866 return if !$volid_hash->{$volid};
5867
5868 my ($updated, $old_size, $new_size) = PVE::QemuServer::Drive::update_disksize($drive, $volid_hash);
5869 if (defined($updated)) {
5870 $changes = 1;
5871 $conf->{$opt} = print_drive($updated);
5872 print "$prefix size of disk '$volid' ($opt) updated from $old_size to $new_size\n";
5873 }
5874 });
91bd6c90 5875
5996a936 5876 # remove 'unusedX' entry if volume is used
ca04977c
FE
5877 PVE::QemuConfig->foreach_unused_volume($conf, sub {
5878 my ($opt, $drive) = @_;
5879
5880 my $volid = $drive->{file};
5881 return if !$volid;
5882
5996a936 5883 my $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
c449137a 5884 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
68b108ee 5885 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
5996a936
DM
5886 $changes = 1;
5887 delete $conf->{$opt};
5888 }
c449137a
DC
5889
5890 $referenced->{$volid} = 1;
5891 $referencedpath->{$path} = 1 if $path;
ca04977c 5892 });
5996a936 5893
91bd6c90
DM
5894 foreach my $volid (sort keys %$volid_hash) {
5895 next if $volid =~ m/vm-$vmid-state-/;
c449137a 5896 next if $referenced->{$volid};
5996a936
DM
5897 my $path = $volid_hash->{$volid}->{path};
5898 next if !$path; # just to be sure
c449137a 5899 next if $referencedpath->{$path};
91bd6c90 5900 $changes = 1;
53b81297 5901 my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
68b108ee 5902 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
c449137a 5903 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
91bd6c90
DM
5904 }
5905
5906 return $changes;
5907}
5908
5909sub rescan {
9224dcee 5910 my ($vmid, $nolock, $dryrun) = @_;
91bd6c90 5911
20519efc 5912 my $cfg = PVE::Storage::config();
91bd6c90 5913
b9a1a3ab
TL
5914 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5915 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
4771526a
AA
5916 foreach my $stor (keys %{$cfg->{ids}}) {
5917 delete($cfg->{ids}->{$stor}) if ! $cfg->{ids}->{$stor}->{content}->{images};
5918 }
5919
53b81297 5920 print "rescan volumes...\n";
91bd6c90
DM
5921 my $volid_hash = scan_volids($cfg, $vmid);
5922
5923 my $updatefn = sub {
5924 my ($vmid) = @_;
5925
ffda963f 5926 my $conf = PVE::QemuConfig->load_config($vmid);
be190583 5927
ffda963f 5928 PVE::QemuConfig->check_lock($conf);
91bd6c90 5929
03da3f0d
DM
5930 my $vm_volids = {};
5931 foreach my $volid (keys %$volid_hash) {
5932 my $info = $volid_hash->{$volid};
5933 $vm_volids->{$volid} = $info if $info->{vmid} && $info->{vmid} == $vmid;
5934 }
5935
68b108ee 5936 my $changes = update_disk_config($vmid, $conf, $vm_volids);
91bd6c90 5937
9224dcee 5938 PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
91bd6c90
DM
5939 };
5940
5941 if (defined($vmid)) {
5942 if ($nolock) {
5943 &$updatefn($vmid);
5944 } else {
ffda963f 5945 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
91bd6c90
DM
5946 }
5947 } else {
5948 my $vmlist = config_list();
5949 foreach my $vmid (keys %$vmlist) {
5950 if ($nolock) {
5951 &$updatefn($vmid);
5952 } else {
ffda963f 5953 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
be190583 5954 }
91bd6c90
DM
5955 }
5956 }
5957}
5958
9f3d73bc
DM
5959sub restore_proxmox_backup_archive {
5960 my ($archive, $vmid, $user, $options) = @_;
5961
5962 my $storecfg = PVE::Storage::config();
5963
5964 my ($storeid, $volname) = PVE::Storage::parse_volume_id($archive);
5965 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5966
5967 my $server = $scfg->{server};
5968 my $datastore = $scfg->{datastore};
5969 my $username = $scfg->{username} // 'root@pam';
5970 my $fingerprint = $scfg->{fingerprint};
5971
5972 my $repo = "$username\@$server:$datastore";
5973 my $password = PVE::Storage::PBSPlugin::pbs_get_password($scfg, $storeid);
5974 local $ENV{PBS_PASSWORD} = $password;
5975 local $ENV{PBS_FINGERPRINT} = $fingerprint if defined($fingerprint);
5976
5977 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
5978 PVE::Storage::parse_volname($storecfg, $archive);
5979
5980 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
5981
5982 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
5983
5984 my $tmpdir = "/var/tmp/vzdumptmp$$";
5985 rmtree $tmpdir;
5986 mkpath $tmpdir;
5987
5988 my $conffile = PVE::QemuConfig->config_file($vmid);
5989 my $tmpfn = "$conffile.$$.tmp";
5990 # disable interrupts (always do cleanups)
5991 local $SIG{INT} =
5992 local $SIG{TERM} =
5993 local $SIG{QUIT} =
5994 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
5995
5996 # Note: $oldconf is undef if VM does not exists
5997 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
5998 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
5999
6000 my $rpcenv = PVE::RPCEnvironment::get();
6001 my $devinfo = {};
6002
6003 eval {
6004 # enable interrupts
6005 local $SIG{INT} =
6006 local $SIG{TERM} =
6007 local $SIG{QUIT} =
6008 local $SIG{HUP} =
6009 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
6010
6011 my $cfgfn = "$tmpdir/qemu-server.conf";
6012 my $firewall_config_fn = "$tmpdir/fw.conf";
6013 my $index_fn = "$tmpdir/index.json";
6014
6015 my $cmd = "restore";
6016
6017 my $param = [$pbs_backup_name, "index.json", $index_fn];
6018 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6019 my $index = PVE::Tools::file_get_contents($index_fn);
6020 $index = decode_json($index);
6021
6022 # print Dumper($index);
6023 foreach my $info (@{$index->{files}}) {
6024 if ($info->{filename} =~ m/^(drive-\S+).img.fidx$/) {
6025 my $devname = $1;
6026 if ($info->{size} =~ m/^(\d+)$/) { # untaint size
6027 $devinfo->{$devname}->{size} = $1;
6028 } else {
6029 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6030 }
6031 }
6032 }
6033
6034 my $is_qemu_server_backup = scalar(grep { $_->{filename} eq 'qemu-server.conf.blob' } @{$index->{files}});
6035 if (!$is_qemu_server_backup) {
6036 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6037 }
6038 my $has_firewall_config = scalar(grep { $_->{filename} eq 'fw.conf.blob' } @{$index->{files}});
6039
6040 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6041 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6042
6043 if ($has_firewall_config) {
6044 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6045 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6046
6047 my $pve_firewall_dir = '/etc/pve/firewall';
6048 mkdir $pve_firewall_dir; # make sure the dir exists
6049 PVE::Tools::file_copy($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6050 }
6051
6052 my $fh = IO::File->new($cfgfn, "r") ||
6053 "unable to read qemu-server.conf - $!\n";
6054
6055 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
6056
6057 # fixme: rate limit?
6058
6059 # create empty/temp config
6060 PVE::Tools::file_set_contents($conffile, "memory: 128\nlock: create");
6061
6062 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6063
6064 # allocate volumes
6065 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6066
6067 foreach my $virtdev (sort keys %$virtdev_hash) {
6068 my $d = $virtdev_hash->{$virtdev};
6069 next if $d->{is_cloudinit}; # no need to restore cloudinit
6070
6071 my $volid = $d->{volid};
6072
6073 my $path = PVE::Storage::path($storecfg, $volid);
9f3d73bc
DM
6074
6075 my $pbs_restore_cmd = [
e400f5e5 6076 '/usr/bin/pbs-restore',
9f3d73bc
DM
6077 '--repository', $repo,
6078 $pbs_backup_name,
e400f5e5
DM
6079 "$d->{devname}.img.fidx",
6080 $path,
9f3d73bc
DM
6081 '--verbose',
6082 ];
6083
e400f5e5
DM
6084 if (PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $volid)) {
6085 push @$pbs_restore_cmd, '--skip-zero';
6086 }
9f3d73bc 6087
e400f5e5 6088 my $dbg_cmdstring = PVE::Tools::cmd2string($pbs_restore_cmd);
9f3d73bc 6089 print "restore proxmox backup image: $dbg_cmdstring\n";
e400f5e5 6090 run_command($pbs_restore_cmd);
9f3d73bc
DM
6091 }
6092
6093 $fh->seek(0, 0) || die "seek failed - $!\n";
6094
6095 my $outfd = new IO::File ($tmpfn, "w") ||
6096 die "unable to write config for VM $vmid\n";
6097
6098 my $cookie = { netcount => 0 };
6099 while (defined(my $line = <$fh>)) {
6100 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $options->{unique});
6101 }
6102
6103 $fh->close();
6104 $outfd->close();
6105 };
6106 my $err = $@;
6107
6108 $restore_deactivate_volumes->($storecfg, $devinfo);
6109
6110 rmtree $tmpdir;
6111
6112 if ($err) {
6113 unlink $tmpfn;
6114 $restore_destroy_volumes->($storecfg, $devinfo);
6115 die $err;
6116 }
6117
6118 rename($tmpfn, $conffile) ||
6119 die "unable to commit configuration file '$conffile'\n";
6120
6121 PVE::Cluster::cfs_update(); # make sure we read new file
6122
6123 eval { rescan($vmid, 1); };
6124 warn $@ if $@;
6125}
6126
91bd6c90
DM
6127sub restore_vma_archive {
6128 my ($archive, $vmid, $user, $opts, $comp) = @_;
6129
91bd6c90
DM
6130 my $readfrom = $archive;
6131
7c536e11
WB
6132 my $cfg = PVE::Storage::config();
6133 my $commands = [];
6134 my $bwlimit = $opts->{bwlimit};
6135
6136 my $dbg_cmdstring = '';
6137 my $add_pipe = sub {
6138 my ($cmd) = @_;
6139 push @$commands, $cmd;
6140 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6141 $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
91bd6c90 6142 $readfrom = '-';
7c536e11
WB
6143 };
6144
6145 my $input = undef;
6146 if ($archive eq '-') {
6147 $input = '<&STDIN';
6148 } else {
6149 # If we use a backup from a PVE defined storage we also consider that
6150 # storage's rate limit:
6151 my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
6152 if (defined($volid)) {
6153 my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
6154 my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
6155 if ($readlimit) {
6156 print STDERR "applying read rate limit: $readlimit\n";
9444c6e4 6157 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
7c536e11
WB
6158 $add_pipe->($cstream);
6159 }
6160 }
6161 }
6162
6163 if ($comp) {
6164 my $cmd;
91bd6c90 6165 if ($comp eq 'gzip') {
7c536e11 6166 $cmd = ['zcat', $readfrom];
91bd6c90 6167 } elsif ($comp eq 'lzop') {
7c536e11 6168 $cmd = ['lzop', '-d', '-c', $readfrom];
91bd6c90
DM
6169 } else {
6170 die "unknown compression method '$comp'\n";
6171 }
7c536e11 6172 $add_pipe->($cmd);
91bd6c90
DM
6173 }
6174
6175 my $tmpdir = "/var/tmp/vzdumptmp$$";
6176 rmtree $tmpdir;
6177
6178 # disable interrupts (always do cleanups)
5b97ef24
TL
6179 local $SIG{INT} =
6180 local $SIG{TERM} =
6181 local $SIG{QUIT} =
6182 local $SIG{HUP} = sub { warn "got interrupt - ignored\n"; };
91bd6c90
DM
6183
6184 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6185 POSIX::mkfifo($mapfifo, 0600);
6186 my $fifofh;
6187
6188 my $openfifo = sub {
6189 open($fifofh, '>', $mapfifo) || die $!;
6190 };
6191
7c536e11 6192 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
91bd6c90
DM
6193
6194 my $oldtimeout;
6195 my $timeout = 5;
6196
6197 my $devinfo = {};
6198
6199 my $rpcenv = PVE::RPCEnvironment::get();
6200
ffda963f 6201 my $conffile = PVE::QemuConfig->config_file($vmid);
91bd6c90
DM
6202 my $tmpfn = "$conffile.$$.tmp";
6203
ae200950 6204 # Note: $oldconf is undef if VM does not exist
ffda963f
FG
6205 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6206 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
ed221350 6207
7c536e11
WB
6208 my %storage_limits;
6209
91bd6c90 6210 my $print_devmap = sub {
91bd6c90
DM
6211 my $cfgfn = "$tmpdir/qemu-server.conf";
6212
6213 # we can read the config - that is already extracted
6214 my $fh = IO::File->new($cfgfn, "r") ||
6215 "unable to read qemu-server.conf - $!\n";
6216
6738ab9c 6217 my $fwcfgfn = "$tmpdir/qemu-server.fw";
3457d090
WL
6218 if (-f $fwcfgfn) {
6219 my $pve_firewall_dir = '/etc/pve/firewall';
6220 mkdir $pve_firewall_dir; # make sure the dir exists
6221 PVE::Tools::file_copy($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6222 }
6738ab9c 6223
9f3d73bc 6224 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
91bd6c90 6225
7c536e11
WB
6226 foreach my $key (keys %storage_limits) {
6227 my $limit = PVE::Storage::get_bandwidth_limit('restore', [$key], $bwlimit);
6228 next if !$limit;
6229 print STDERR "rate limit for storage $key: $limit KiB/s\n";
6230 $storage_limits{$key} = $limit * 1024;
6231 }
6232
91bd6c90 6233 foreach my $devname (keys %$devinfo) {
be190583
DM
6234 die "found no device mapping information for device '$devname'\n"
6235 if !$devinfo->{$devname}->{virtdev};
91bd6c90
DM
6236 }
6237
ed221350 6238 # create empty/temp config
be190583 6239 if ($oldconf) {
ed221350 6240 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
d1e92cf6 6241 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
ed221350
DM
6242 }
6243
9f3d73bc
DM
6244 # allocate volumes
6245 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
6246
6247 # print restore information to $fifofh
91bd6c90
DM
6248 foreach my $virtdev (sort keys %$virtdev_hash) {
6249 my $d = $virtdev_hash->{$virtdev};
9f3d73bc
DM
6250 next if $d->{is_cloudinit}; # no need to restore cloudinit
6251
7c536e11 6252 my $storeid = $d->{storeid};
9f3d73bc 6253 my $volid = $d->{volid};
7c536e11
WB
6254
6255 my $map_opts = '';
6256 if (my $limit = $storage_limits{$storeid}) {
6257 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6258 }
8fd57431 6259
91bd6c90 6260 my $write_zeros = 1;
88240a83 6261 if (PVE::Storage::volume_has_feature($cfg, 'sparseinit', $volid)) {
91bd6c90
DM
6262 $write_zeros = 0;
6263 }
6264
9f3d73bc 6265 my $path = PVE::Storage::path($cfg, $volid);
87056e18 6266
9f3d73bc 6267 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
91bd6c90 6268
9f3d73bc 6269 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
91bd6c90
DM
6270 }
6271
6272 $fh->seek(0, 0) || die "seek failed - $!\n";
6273
6274 my $outfd = new IO::File ($tmpfn, "w") ||
6275 die "unable to write config for VM $vmid\n";
6276
6277 my $cookie = { netcount => 0 };
6278 while (defined(my $line = <$fh>)) {
9f3d73bc 6279 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
91bd6c90
DM
6280 }
6281
6282 $fh->close();
6283 $outfd->close();
6284 };
6285
6286 eval {
6287 # enable interrupts
6cb0144a
EK
6288 local $SIG{INT} =
6289 local $SIG{TERM} =
6290 local $SIG{QUIT} =
6291 local $SIG{HUP} =
6292 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
91bd6c90
DM
6293 local $SIG{ALRM} = sub { die "got timeout\n"; };
6294
6295 $oldtimeout = alarm($timeout);
6296
6297 my $parser = sub {
6298 my $line = shift;
6299
6300 print "$line\n";
6301
6302 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6303 my ($dev_id, $size, $devname) = ($1, $2, $3);
6304 $devinfo->{$devname} = { size => $size, dev_id => $dev_id };
6305 } elsif ($line =~ m/^CTIME: /) {
46f58b5f 6306 # we correctly received the vma config, so we can disable
3cf90d7a
DM
6307 # the timeout now for disk allocation (set to 10 minutes, so
6308 # that we always timeout if something goes wrong)
6309 alarm(600);
91bd6c90
DM
6310 &$print_devmap();
6311 print $fifofh "done\n";
6312 my $tmp = $oldtimeout || 0;
6313 $oldtimeout = undef;
6314 alarm($tmp);
6315 close($fifofh);
6316 }
6317 };
be190583 6318
7c536e11
WB
6319 print "restore vma archive: $dbg_cmdstring\n";
6320 run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
91bd6c90
DM
6321 };
6322 my $err = $@;
6323
6324 alarm($oldtimeout) if $oldtimeout;
6325
9f3d73bc 6326 $restore_deactivate_volumes->($cfg, $devinfo);
5f96f4df 6327
91bd6c90 6328 unlink $mapfifo;
9f3d73bc 6329 rmtree $tmpdir;
91bd6c90
DM
6330
6331 if ($err) {
91bd6c90 6332 unlink $tmpfn;
9f3d73bc 6333 $restore_destroy_volumes->($cfg, $devinfo);
91bd6c90
DM
6334 die $err;
6335 }
6336
ed221350 6337 rename($tmpfn, $conffile) ||
91bd6c90
DM
6338 die "unable to commit configuration file '$conffile'\n";
6339
ed221350
DM
6340 PVE::Cluster::cfs_update(); # make sure we read new file
6341
91bd6c90
DM
6342 eval { rescan($vmid, 1); };
6343 warn $@ if $@;
6344}
6345
6346sub restore_tar_archive {
6347 my ($archive, $vmid, $user, $opts) = @_;
6348
9c502e26 6349 if ($archive ne '-') {
ed221350 6350 my $firstfile = tar_archive_read_firstfile($archive);
9c502e26
DM
6351 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6352 if $firstfile ne 'qemu-server.conf';
6353 }
3e16d5fc 6354
20519efc 6355 my $storecfg = PVE::Storage::config();
ebb55558 6356
4b026937
TL
6357 # avoid zombie disks when restoring over an existing VM -> cleanup first
6358 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6359 # skiplock=1 because qmrestore has set the 'create' lock itself already
ffda963f 6360 my $vmcfgfn = PVE::QemuConfig->config_file($vmid);
b04ea584 6361 destroy_vm($storecfg, $vmid, 1, { lock => 'restore' }) if -f $vmcfgfn;
ed221350 6362
3e16d5fc
DM
6363 my $tocmd = "/usr/lib/qemu-server/qmextract";
6364
2415a446 6365 $tocmd .= " --storage " . PVE::Tools::shellquote($opts->{storage}) if $opts->{storage};
a0d1b1a2 6366 $tocmd .= " --pool " . PVE::Tools::shellquote($opts->{pool}) if $opts->{pool};
3e16d5fc
DM
6367 $tocmd .= ' --prealloc' if $opts->{prealloc};
6368 $tocmd .= ' --info' if $opts->{info};
6369
a0d1b1a2 6370 # tar option "xf" does not autodetect compression when read from STDIN,
9c502e26 6371 # so we pipe to zcat
2415a446
DM
6372 my $cmd = "zcat -f|tar xf " . PVE::Tools::shellquote($archive) . " " .
6373 PVE::Tools::shellquote("--to-command=$tocmd");
3e16d5fc
DM
6374
6375 my $tmpdir = "/var/tmp/vzdumptmp$$";
6376 mkpath $tmpdir;
6377
6378 local $ENV{VZDUMP_TMPDIR} = $tmpdir;
6379 local $ENV{VZDUMP_VMID} = $vmid;
a0d1b1a2 6380 local $ENV{VZDUMP_USER} = $user;
3e16d5fc 6381
ffda963f 6382 my $conffile = PVE::QemuConfig->config_file($vmid);
3e16d5fc
DM
6383 my $tmpfn = "$conffile.$$.tmp";
6384
6385 # disable interrupts (always do cleanups)
6cb0144a
EK
6386 local $SIG{INT} =
6387 local $SIG{TERM} =
6388 local $SIG{QUIT} =
6389 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
3e16d5fc 6390
afdb31d5 6391 eval {
3e16d5fc 6392 # enable interrupts
6cb0144a
EK
6393 local $SIG{INT} =
6394 local $SIG{TERM} =
6395 local $SIG{QUIT} =
6396 local $SIG{HUP} =
6397 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
3e16d5fc 6398
9c502e26
DM
6399 if ($archive eq '-') {
6400 print "extracting archive from STDIN\n";
6401 run_command($cmd, input => "<&STDIN");
6402 } else {
6403 print "extracting archive '$archive'\n";
6404 run_command($cmd);
6405 }
3e16d5fc
DM
6406
6407 return if $opts->{info};
6408
6409 # read new mapping
6410 my $map = {};
6411 my $statfile = "$tmpdir/qmrestore.stat";
6412 if (my $fd = IO::File->new($statfile, "r")) {
6413 while (defined (my $line = <$fd>)) {
6414 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6415 $map->{$1} = $2 if $1;
6416 } else {
6417 print STDERR "unable to parse line in statfile - $line\n";
6418 }
6419 }
6420 $fd->close();
6421 }
6422
6423 my $confsrc = "$tmpdir/qemu-server.conf";
6424
6425 my $srcfd = new IO::File($confsrc, "r") ||
6426 die "unable to open file '$confsrc'\n";
6427
6428 my $outfd = new IO::File ($tmpfn, "w") ||
6429 die "unable to write config for VM $vmid\n";
6430
91bd6c90 6431 my $cookie = { netcount => 0 };
3e16d5fc 6432 while (defined (my $line = <$srcfd>)) {
9f3d73bc 6433 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
3e16d5fc
DM
6434 }
6435
6436 $srcfd->close();
6437 $outfd->close();
6438 };
7dc7f315 6439 if (my $err = $@) {
3e16d5fc 6440 unlink $tmpfn;
ed221350 6441 tar_restore_cleanup($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info};
3e16d5fc 6442 die $err;
afdb31d5 6443 }
3e16d5fc
DM
6444
6445 rmtree $tmpdir;
6446
6447 rename $tmpfn, $conffile ||
6448 die "unable to commit configuration file '$conffile'\n";
91bd6c90 6449
ed221350
DM
6450 PVE::Cluster::cfs_update(); # make sure we read new file
6451
91bd6c90
DM
6452 eval { rescan($vmid, 1); };
6453 warn $@ if $@;
3e16d5fc
DM
6454};
6455
65a5ce88 6456sub foreach_storage_used_by_vm {
18bfb361
DM
6457 my ($conf, $func) = @_;
6458
6459 my $sidhash = {};
6460
8ddbcf8b
FG
6461 foreach_drive($conf, sub {
6462 my ($ds, $drive) = @_;
6463 return if drive_is_cdrom($drive);
18bfb361
DM
6464
6465 my $volid = $drive->{file};
6466
6467 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
be190583 6468 $sidhash->{$sid} = $sid if $sid;
8ddbcf8b 6469 });
18bfb361
DM
6470
6471 foreach my $sid (sort keys %$sidhash) {
6472 &$func($sid);
6473 }
6474}
6475
6c9f59c1
TL
6476my $qemu_snap_storage = {
6477 rbd => 1,
6478};
e5eaa028
WL
6479sub do_snapshots_with_qemu {
6480 my ($storecfg, $volid) = @_;
6481
6482 my $storage_name = PVE::Storage::parse_volume_id($volid);
8aa2ed7c 6483 my $scfg = $storecfg->{ids}->{$storage_name};
e5eaa028 6484
8aa2ed7c 6485 if ($qemu_snap_storage->{$scfg->{type}} && !$scfg->{krbd}){
e5eaa028
WL
6486 return 1;
6487 }
6488
6489 if ($volid =~ m/\.(qcow2|qed)$/){
6490 return 1;
6491 }
6492
6493 return undef;
6494}
6495
4dcc780c 6496sub qga_check_running {
a4938c72 6497 my ($vmid, $nowarn) = @_;
4dcc780c 6498
0a13e08e 6499 eval { mon_cmd($vmid, "guest-ping", timeout => 3); };
4dcc780c 6500 if ($@) {
a4938c72 6501 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
4dcc780c
WL
6502 return 0;
6503 }
6504 return 1;
6505}
6506
04a69bb4
AD
6507sub template_create {
6508 my ($vmid, $conf, $disk) = @_;
6509
04a69bb4 6510 my $storecfg = PVE::Storage::config();
04a69bb4 6511
9cd07842
DM
6512 foreach_drive($conf, sub {
6513 my ($ds, $drive) = @_;
6514
6515 return if drive_is_cdrom($drive);
6516 return if $disk && $ds ne $disk;
6517
6518 my $volid = $drive->{file};
bbd56097 6519 return if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
9cd07842 6520
04a69bb4
AD
6521 my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
6522 $drive->{file} = $voliddst;
71c58bb7 6523 $conf->{$ds} = print_drive($drive);
ffda963f 6524 PVE::QemuConfig->write_config($vmid, $conf);
04a69bb4 6525 });
04a69bb4
AD
6526}
6527
92bdc3f0
DC
6528sub convert_iscsi_path {
6529 my ($path) = @_;
6530
6531 if ($path =~ m|^iscsi://([^/]+)/([^/]+)/(.+)$|) {
6532 my $portal = $1;
6533 my $target = $2;
6534 my $lun = $3;
6535
6536 my $initiator_name = get_initiator_name();
6537
6538 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6539 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6540 }
6541
6542 die "cannot convert iscsi path '$path', unkown format\n";
6543}
6544
5133de42 6545sub qemu_img_convert {
988e2714 6546 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5133de42
AD
6547
6548 my $storecfg = PVE::Storage::config();
6549 my ($src_storeid, $src_volname) = PVE::Storage::parse_volume_id($src_volid, 1);
6550 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
6551
af1f1ec0 6552 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6bb91c17 6553
af1f1ec0
DC
6554 my $cachemode;
6555 my $src_path;
6556 my $src_is_iscsi = 0;
bdd1feef 6557 my $src_format;
6bb91c17 6558
af1f1ec0
DC
6559 if ($src_storeid) {
6560 PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
5133de42 6561 my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
af1f1ec0
DC
6562 $src_format = qemu_img_format($src_scfg, $src_volname);
6563 $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
6564 $src_is_iscsi = ($src_path =~ m|^iscsi://|);
6565 $cachemode = 'none' if $src_scfg->{type} eq 'zfspool';
6566 } elsif (-f $src_volid) {
6567 $src_path = $src_volid;
e0fd2b2f 6568 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
af1f1ec0
DC
6569 $src_format = $1;
6570 }
6571 }
5133de42 6572
af1f1ec0 6573 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
5133de42 6574
af1f1ec0
DC
6575 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
6576 my $dst_format = qemu_img_format($dst_scfg, $dst_volname);
6577 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
6578 my $dst_is_iscsi = ($dst_path =~ m|^iscsi://|);
5133de42 6579
af1f1ec0
DC
6580 my $cmd = [];
6581 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
bdd1feef
TL
6582 push @$cmd, '-l', "snapshot.name=$snapname"
6583 if $snapname && $src_format && $src_format eq "qcow2";
af1f1ec0
DC
6584 push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
6585 push @$cmd, '-T', $cachemode if defined($cachemode);
6586
6587 if ($src_is_iscsi) {
6588 push @$cmd, '--image-opts';
6589 $src_path = convert_iscsi_path($src_path);
bdd1feef 6590 } elsif ($src_format) {
af1f1ec0
DC
6591 push @$cmd, '-f', $src_format;
6592 }
92bdc3f0 6593
af1f1ec0
DC
6594 if ($dst_is_iscsi) {
6595 push @$cmd, '--target-image-opts';
6596 $dst_path = convert_iscsi_path($dst_path);
6597 } else {
6598 push @$cmd, '-O', $dst_format;
6599 }
92bdc3f0 6600
af1f1ec0 6601 push @$cmd, $src_path;
92bdc3f0 6602
af1f1ec0
DC
6603 if (!$dst_is_iscsi && $is_zero_initialized) {
6604 push @$cmd, "zeroinit:$dst_path";
6605 } else {
6606 push @$cmd, $dst_path;
6607 }
92bdc3f0 6608
af1f1ec0
DC
6609 my $parser = sub {
6610 my $line = shift;
6611 if($line =~ m/\((\S+)\/100\%\)/){
6612 my $percent = $1;
6613 my $transferred = int($size * $percent / 100);
6614 my $remaining = $size - $transferred;
92bdc3f0 6615
af1f1ec0 6616 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
988e2714 6617 }
5133de42 6618
af1f1ec0 6619 };
5133de42 6620
af1f1ec0
DC
6621 eval { run_command($cmd, timeout => undef, outfunc => $parser); };
6622 my $err = $@;
6623 die "copy failed: $err" if $err;
5133de42
AD
6624}
6625
6626sub qemu_img_format {
6627 my ($scfg, $volname) = @_;
6628
e0fd2b2f 6629 if ($scfg->{path} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
5133de42 6630 return $1;
be190583 6631 } else {
5133de42 6632 return "raw";
5133de42
AD
6633 }
6634}
6635
cfad42af 6636sub qemu_drive_mirror {
bc6c8231 6637 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
cfad42af 6638
5a345967
AD
6639 $jobs = {} if !$jobs;
6640
6641 my $qemu_target;
6642 my $format;
35e4ab04 6643 $jobs->{"drive-$drive"} = {};
152fe752 6644
1e5143de 6645 if ($dst_volid =~ /^nbd:/) {
87955688 6646 $qemu_target = $dst_volid;
5a345967 6647 $format = "nbd";
5a345967 6648 } else {
5a345967
AD
6649 my $storecfg = PVE::Storage::config();
6650 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
6651
6652 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
cfad42af 6653
5a345967 6654 $format = qemu_img_format($dst_scfg, $dst_volname);
21ccdb50 6655
5a345967 6656 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
21ccdb50 6657
5a345967
AD
6658 $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
6659 }
988e2714
WB
6660
6661 my $opts = { timeout => 10, device => "drive-$drive", mode => "existing", sync => "full", target => $qemu_target };
88383920
DM
6662 $opts->{format} = $format if $format;
6663
bc6c8231
FG
6664 if (defined($src_bitmap)) {
6665 $opts->{sync} = 'incremental';
6666 $opts->{bitmap} = $src_bitmap;
6667 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
6668 }
6669
9fa05d31 6670 if (defined($bwlimit)) {
f6409f61
TL
6671 $opts->{speed} = $bwlimit * 1024;
6672 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
9fa05d31
SI
6673 } else {
6674 print "drive mirror is starting for drive-$drive\n";
6675 }
21ccdb50 6676
6dde5ea2 6677 # if a job already runs for this device we get an error, catch it for cleanup
0a13e08e 6678 eval { mon_cmd($vmid, "drive-mirror", %$opts); };
5a345967
AD
6679 if (my $err = $@) {
6680 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6dde5ea2
TL
6681 warn "$@\n" if $@;
6682 die "mirroring error: $err\n";
5a345967
AD
6683 }
6684
e02fb126 6685 qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $completion, $qga);
5a345967
AD
6686}
6687
db1f8b39
FG
6688# $completion can be either
6689# 'complete': wait until all jobs are ready, block-job-complete them (default)
6690# 'cancel': wait until all jobs are ready, block-job-cancel them
6691# 'skip': wait until all jobs are ready, return with block jobs in ready state
5a345967 6692sub qemu_drive_mirror_monitor {
e02fb126
ML
6693 my ($vmid, $vmiddst, $jobs, $completion, $qga) = @_;
6694
db1f8b39 6695 $completion //= 'complete';
2e953867 6696
08ac653f 6697 eval {
5a345967
AD
6698 my $err_complete = 0;
6699
08ac653f 6700 while (1) {
5a345967
AD
6701 die "storage migration timed out\n" if $err_complete > 300;
6702
0a13e08e 6703 my $stats = mon_cmd($vmid, "query-block-jobs");
08ac653f 6704
5a345967
AD
6705 my $running_mirror_jobs = {};
6706 foreach my $stat (@$stats) {
6707 next if $stat->{type} ne 'mirror';
6708 $running_mirror_jobs->{$stat->{device}} = $stat;
6709 }
08ac653f 6710
5a345967 6711 my $readycounter = 0;
67fb9de6 6712
5a345967
AD
6713 foreach my $job (keys %$jobs) {
6714
6715 if(defined($jobs->{$job}->{complete}) && !defined($running_mirror_jobs->{$job})) {
6716 print "$job : finished\n";
6717 delete $jobs->{$job};
6718 next;
6719 }
6720
bd2d5fe6 6721 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
f34ebd52 6722
5a345967
AD
6723 my $busy = $running_mirror_jobs->{$job}->{busy};
6724 my $ready = $running_mirror_jobs->{$job}->{ready};
6725 if (my $total = $running_mirror_jobs->{$job}->{len}) {
6726 my $transferred = $running_mirror_jobs->{$job}->{offset} || 0;
6727 my $remaining = $total - $transferred;
6728 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
08ac653f 6729
5a345967
AD
6730 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6731 }
f34ebd52 6732
d1782eba 6733 $readycounter++ if $running_mirror_jobs->{$job}->{ready};
5a345967 6734 }
b467f79a 6735
5a345967
AD
6736 last if scalar(keys %$jobs) == 0;
6737
6738 if ($readycounter == scalar(keys %$jobs)) {
6739 print "all mirroring jobs are ready \n";
e02fb126 6740 last if $completion eq 'skip'; #do the complete later
5a345967
AD
6741
6742 if ($vmiddst && $vmiddst != $vmid) {
1a988fd2
DC
6743 my $agent_running = $qga && qga_check_running($vmid);
6744 if ($agent_running) {
5619e74a 6745 print "freeze filesystem\n";
0a13e08e 6746 eval { mon_cmd($vmid, "guest-fsfreeze-freeze"); };
5619e74a
AD
6747 } else {
6748 print "suspend vm\n";
6749 eval { PVE::QemuServer::vm_suspend($vmid, 1); };
6750 }
6751
5a345967
AD
6752 # if we clone a disk for a new target vm, we don't switch the disk
6753 PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
5619e74a 6754
1a988fd2 6755 if ($agent_running) {
5619e74a 6756 print "unfreeze filesystem\n";
0a13e08e 6757 eval { mon_cmd($vmid, "guest-fsfreeze-thaw"); };
5619e74a
AD
6758 } else {
6759 print "resume vm\n";
6760 eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
6761 }
6762
2e953867 6763 last;
5a345967
AD
6764 } else {
6765
6766 foreach my $job (keys %$jobs) {
6767 # try to switch the disk if source and destination are on the same guest
bd2d5fe6 6768 print "$job: Completing block job...\n";
5a345967 6769
e02fb126 6770 my $op;
db1f8b39 6771 if ($completion eq 'complete') {
e02fb126 6772 $op = 'block-job-complete';
db1f8b39 6773 } elsif ($completion eq 'cancel') {
e02fb126
ML
6774 $op = 'block-job-cancel';
6775 } else {
6776 die "invalid completion value: $completion\n";
6777 }
6778 eval { mon_cmd($vmid, $op, device => $job) };
5a345967 6779 if ($@ =~ m/cannot be completed/) {
bd2d5fe6 6780 print "$job: Block job cannot be completed, try again.\n";
5a345967
AD
6781 $err_complete++;
6782 }else {
bd2d5fe6 6783 print "$job: Completed successfully.\n";
5a345967
AD
6784 $jobs->{$job}->{complete} = 1;
6785 }
6786 }
2e953867 6787 }
08ac653f 6788 }
08ac653f 6789 sleep 1;
cfad42af 6790 }
08ac653f 6791 };
88383920 6792 my $err = $@;
08ac653f 6793
88383920 6794 if ($err) {
5a345967 6795 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
88383920
DM
6796 die "mirroring error: $err";
6797 }
6798
5a345967
AD
6799}
6800
6801sub qemu_blockjobs_cancel {
6802 my ($vmid, $jobs) = @_;
6803
6804 foreach my $job (keys %$jobs) {
bd2d5fe6 6805 print "$job: Cancelling block job\n";
0a13e08e 6806 eval { mon_cmd($vmid, "block-job-cancel", device => $job); };
5a345967
AD
6807 $jobs->{$job}->{cancel} = 1;
6808 }
6809
6810 while (1) {
0a13e08e 6811 my $stats = mon_cmd($vmid, "query-block-jobs");
5a345967
AD
6812
6813 my $running_jobs = {};
6814 foreach my $stat (@$stats) {
6815 $running_jobs->{$stat->{device}} = $stat;
6816 }
6817
6818 foreach my $job (keys %$jobs) {
6819
bd2d5fe6
WB
6820 if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
6821 print "$job: Done.\n";
5a345967
AD
6822 delete $jobs->{$job};
6823 }
6824 }
6825
6826 last if scalar(keys %$jobs) == 0;
6827
6828 sleep 1;
cfad42af
AD
6829 }
6830}
6831
152fe752 6832sub clone_disk {
be190583 6833 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
818ce80e 6834 $newvmid, $storage, $format, $full, $newvollist, $jobs, $completion, $qga, $bwlimit, $conf) = @_;
152fe752
DM
6835
6836 my $newvolid;
6837
6838 if (!$full) {
6839 print "create linked clone of drive $drivename ($drive->{file})\n";
258e646c 6840 $newvolid = PVE::Storage::vdisk_clone($storecfg, $drive->{file}, $newvmid, $snapname);
152fe752
DM
6841 push @$newvollist, $newvolid;
6842 } else {
5a345967 6843
152fe752
DM
6844 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
6845 $storeid = $storage if $storage;
6846
44549149 6847 my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format);
152fe752
DM
6848 my ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 3);
6849
6850 print "create full clone of drive $drivename ($drive->{file})\n";
931432bd 6851 my $name = undef;
7fe8b44c
TL
6852 if (drive_is_cloudinit($drive)) {
6853 $name = "vm-$newvmid-cloudinit";
6854 $name .= ".$dst_format" if $dst_format ne 'raw';
6855 $snapname = undef;
6856 $size = PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE;
818ce80e
DC
6857 } elsif ($drivename eq 'efidisk0') {
6858 $size = get_efivars_size($conf);
7fe8b44c 6859 }
931432bd 6860 $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
152fe752
DM
6861 push @$newvollist, $newvolid;
6862
3999f370 6863 PVE::Storage::activate_volumes($storecfg, [$newvolid]);
1dbd6d30 6864
7fe8b44c
TL
6865 if (drive_is_cloudinit($drive)) {
6866 goto no_data_clone;
6867 }
6868
988e2714 6869 my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
152fe752 6870 if (!$running || $snapname) {
d189e590 6871 # TODO: handle bwlimits
818ce80e
DC
6872 if ($drivename eq 'efidisk0') {
6873 # the relevant data on the efidisk may be smaller than the source
6874 # e.g. on RBD/ZFS, so we use dd to copy only the amount
6875 # that is given by the OVMF_VARS.fd
6876 my $src_path = PVE::Storage::path($storecfg, $drive->{file});
6877 my $dst_path = PVE::Storage::path($storecfg, $newvolid);
6878 run_command(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=1", "count=$size", "if=$src_path", "of=$dst_path"]);
6879 } else {
6880 qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
6881 }
152fe752 6882 } else {
2e541679
AD
6883
6884 my $kvmver = get_running_qemu_version ($vmid);
2ea5fb7e 6885 if (!min_version($kvmver, 2, 7)) {
961af8a3
WB
6886 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6887 if $drive->{iothread};
2e541679 6888 }
2af848a2 6889
db1f8b39 6890 qemu_drive_mirror($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $completion, $qga, $bwlimit);
be190583 6891 }
152fe752
DM
6892 }
6893
7fe8b44c 6894no_data_clone:
152fe752
DM
6895 my ($size) = PVE::Storage::volume_size_info($storecfg, $newvolid, 3);
6896
6897 my $disk = $drive;
6898 $disk->{format} = undef;
6899 $disk->{file} = $newvolid;
6900 $disk->{size} = $size;
6901
6902 return $disk;
6903}
6904
98cfd8b6
AD
6905sub get_running_qemu_version {
6906 my ($vmid) = @_;
0a13e08e 6907 my $res = mon_cmd($vmid, "query-version");
98cfd8b6
AD
6908 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6909}
6910
249c4a6c
AD
6911sub qemu_use_old_bios_files {
6912 my ($machine_type) = @_;
6913
6914 return if !$machine_type;
6915
6916 my $use_old_bios_files = undef;
6917
6918 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6919 $machine_type = $1;
6920 $use_old_bios_files = 1;
6921 } else {
9471e48b 6922 my $version = PVE::QemuServer::Machine::extract_version($machine_type, kvm_user_version());
249c4a6c
AD
6923 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6924 # load new efi bios files on migration. So this hack is required to allow
6925 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6926 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
2ea5fb7e 6927 $use_old_bios_files = !min_version($version, 2, 4);
249c4a6c
AD
6928 }
6929
6930 return ($use_old_bios_files, $machine_type);
6931}
6932
818ce80e
DC
6933sub get_efivars_size {
6934 my ($conf) = @_;
6935 my $arch = get_vm_arch($conf);
6936 my (undef, $ovmf_vars) = get_ovmf_files($arch);
6937 die "uefi vars image '$ovmf_vars' not found\n" if ! -f $ovmf_vars;
6938 return -s $ovmf_vars;
6939}
6940
6941sub update_efidisk_size {
6942 my ($conf) = @_;
6943
6944 return if !defined($conf->{efidisk0});
6945
6946 my $disk = PVE::QemuServer::parse_drive('efidisk0', $conf->{efidisk0});
6947 $disk->{size} = get_efivars_size($conf);
6948 $conf->{efidisk0} = print_drive($disk);
6949
6950 return;
6951}
6952
96ed3574
WB
6953sub create_efidisk($$$$$) {
6954 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
3e1f1122 6955
96ed3574
WB
6956 my (undef, $ovmf_vars) = get_ovmf_files($arch);
6957 die "EFI vars default image not found\n" if ! -f $ovmf_vars;
3e1f1122 6958
af1f1ec0
DC
6959 my $vars_size_b = -s $ovmf_vars;
6960 my $vars_size = PVE::Tools::convert_size($vars_size_b, 'b' => 'kb');
3e1f1122
TL
6961 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6962 PVE::Storage::activate_volumes($storecfg, [$volid]);
6963
af1f1ec0 6964 qemu_img_convert($ovmf_vars, $volid, $vars_size_b, undef, 0);
340dbcf7 6965 my ($size) = PVE::Storage::volume_size_info($storecfg, $volid, 3);
3e1f1122 6966
340dbcf7 6967 return ($volid, $size/1024);
3e1f1122
TL
6968}
6969
22de899a
AD
6970sub vm_iothreads_list {
6971 my ($vmid) = @_;
6972
0a13e08e 6973 my $res = mon_cmd($vmid, 'query-iothreads');
22de899a
AD
6974
6975 my $iothreads = {};
6976 foreach my $iothread (@$res) {
6977 $iothreads->{ $iothread->{id} } = $iothread->{"thread-id"};
6978 }
6979
6980 return $iothreads;
6981}
6982
ee034f5c
AD
6983sub scsihw_infos {
6984 my ($conf, $drive) = @_;
6985
6986 my $maxdev = 0;
6987
7fe1b688 6988 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
ee034f5c 6989 $maxdev = 7;
a1511b3c 6990 } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
ee034f5c
AD
6991 $maxdev = 1;
6992 } else {
6993 $maxdev = 256;
6994 }
6995
6996 my $controller = int($drive->{index} / $maxdev);
a1511b3c 6997 my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') ? "virtioscsi" : "scsihw";
ee034f5c
AD
6998
6999 return ($maxdev, $controller, $controller_prefix);
7000}
a1511b3c 7001
4317f69f
AD
7002sub windows_version {
7003 my ($ostype) = @_;
7004
7005 return 0 if !$ostype;
7006
7007 my $winversion = 0;
7008
7009 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7010 $winversion = 5;
7011 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7012 $winversion = 6;
7013 } elsif ($ostype =~ m/^win(\d+)$/) {
7014 $winversion = $1;
7015 }
7016
7017 return $winversion;
7018}
7019
44549149
EK
7020sub resolve_dst_disk_format {
7021 my ($storecfg, $storeid, $src_volname, $format) = @_;
7022 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
7023
7024 if (!$format) {
7025 # if no target format is specified, use the source disk format as hint
7026 if ($src_volname) {
7027 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7028 $format = qemu_img_format($scfg, $src_volname);
7029 } else {
7030 return $defFormat;
7031 }
7032 }
7033
7034 # test if requested format is supported - else use default
7035 my $supported = grep { $_ eq $format } @$validFormats;
7036 $format = $defFormat if !$supported;
7037 return $format;
7038}
7039
66cebc46
DC
7040# NOTE: if this logic changes, please update docs & possibly gui logic
7041sub find_vmstate_storage {
7042 my ($conf, $storecfg) = @_;
7043
7044 # first, return storage from conf if set
7045 return $conf->{vmstatestorage} if $conf->{vmstatestorage};
7046
7047 my ($target, $shared, $local);
7048
7049 foreach_storage_used_by_vm($conf, sub {
7050 my ($sid) = @_;
7051 my $scfg = PVE::Storage::storage_config($storecfg, $sid);
7052 my $dst = $scfg->{shared} ? \$shared : \$local;
7053 $$dst = $sid if !$$dst || $scfg->{path}; # prefer file based storage
7054 });
7055
7056 # second, use shared storage where VM has at least one disk
7057 # third, use local storage where VM has at least one disk
7058 # fall back to local storage
7059 $target = $shared // $local // 'local';
7060
7061 return $target;
7062}
7063
6ee499ff 7064sub generate_uuid {
ae2fcb3b
EK
7065 my ($uuid, $uuid_str);
7066 UUID::generate($uuid);
7067 UUID::unparse($uuid, $uuid_str);
6ee499ff
DC
7068 return $uuid_str;
7069}
7070
7071sub generate_smbios1_uuid {
7072 return "uuid=".generate_uuid();
ae2fcb3b
EK
7073}
7074
9c152e87
TL
7075sub nbd_stop {
7076 my ($vmid) = @_;
7077
0a13e08e 7078 mon_cmd($vmid, 'nbd-server-stop');
9c152e87
TL
7079}
7080
dae98db9
DC
7081sub create_reboot_request {
7082 my ($vmid) = @_;
7083 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7084 or die "failed to create reboot trigger file: $!\n";
7085 close($fh);
7086}
7087
7088sub clear_reboot_request {
7089 my ($vmid) = @_;
7090 my $path = "/run/qemu-server/$vmid.reboot";
7091 my $res = 0;
7092
7093 $res = unlink($path);
7094 die "could not remove reboot request for $vmid: $!"
7095 if !$res && $! != POSIX::ENOENT;
7096
7097 return $res;
7098}
7099
65e866e5
DM
7100# bash completion helper
7101
7102sub complete_backup_archives {
7103 my ($cmdname, $pname, $cvalue) = @_;
7104
7105 my $cfg = PVE::Storage::config();
7106
7107 my $storeid;
7108
7109 if ($cvalue =~ m/^([^:]+):/) {
7110 $storeid = $1;
7111 }
7112
7113 my $data = PVE::Storage::template_list($cfg, $storeid, 'backup');
7114
7115 my $res = [];
7116 foreach my $id (keys %$data) {
7117 foreach my $item (@{$data->{$id}}) {
7118 next if $item->{format} !~ m/^vma\.(gz|lzo)$/;
7119 push @$res, $item->{volid} if defined($item->{volid});
7120 }
7121 }
7122
7123 return $res;
7124}
7125
7126my $complete_vmid_full = sub {
7127 my ($running) = @_;
7128
7129 my $idlist = vmstatus();
7130
7131 my $res = [];
7132
7133 foreach my $id (keys %$idlist) {
7134 my $d = $idlist->{$id};
7135 if (defined($running)) {
7136 next if $d->{template};
7137 next if $running && $d->{status} ne 'running';
7138 next if !$running && $d->{status} eq 'running';
7139 }
7140 push @$res, $id;
7141
7142 }
7143 return $res;
7144};
7145
7146sub complete_vmid {
7147 return &$complete_vmid_full();
7148}
7149
7150sub complete_vmid_stopped {
7151 return &$complete_vmid_full(0);
7152}
7153
7154sub complete_vmid_running {
7155 return &$complete_vmid_full(1);
7156}
7157
335af808
DM
7158sub complete_storage {
7159
7160 my $cfg = PVE::Storage::config();
7161 my $ids = $cfg->{ids};
7162
7163 my $res = [];
7164 foreach my $sid (keys %$ids) {
7165 next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
c4c844ef 7166 next if !$ids->{$sid}->{content}->{images};
335af808
DM
7167 push @$res, $sid;
7168 }
7169
7170 return $res;
7171}
7172
255e9c54
AL
7173sub complete_migration_storage {
7174 my ($cmd, $param, $current_value, $all_args) = @_;
7175
7176 my $targetnode = @$all_args[1];
7177
7178 my $cfg = PVE::Storage::config();
7179 my $ids = $cfg->{ids};
7180
7181 my $res = [];
7182 foreach my $sid (keys %$ids) {
7183 next if !PVE::Storage::storage_check_enabled($cfg, $sid, $targetnode, 1);
7184 next if !$ids->{$sid}->{content}->{images};
7185 push @$res, $sid;
7186 }
7187
7188 return $res;
7189}
7190
1e3baf05 71911;