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