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