1 package PVE
::QemuServer
;
11 use File
::Copy
qw(copy);
24 use Storable
qw(dclone);
25 use Time
::HiRes
qw(gettimeofday);
29 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
30 use PVE
::DataCenterConfig
;
31 use PVE
::Exception
qw(raise raise_param_exc);
32 use PVE
::GuestHelpers
qw(safe_string_ne safe_num_ne safe_boolean_ne);
34 use PVE
::JSONSchema
qw(get_standard_option);
36 use PVE
::RPCEnvironment
;
40 use PVE
::Tools
qw(run_command lock_file lock_file_full file_read_firstline file_get_contents dir_glob_foreach get_host_arch $IPV6RE);
44 use PVE
::QemuServer
::Helpers
qw(min_version config_aware_timeout);
45 use PVE
::QemuServer
::Cloudinit
;
46 use PVE
::QemuServer
::CPUConfig
qw(print_cpu_device get_cpu_options);
47 use PVE
::QemuServer
::Drive
qw(is_valid_drivename drive_is_cloudinit drive_is_cdrom parse_drive print_drive foreach_drive foreach_volid);
48 use PVE
::QemuServer
::Machine
;
49 use PVE
::QemuServer
::Memory
;
50 use PVE
::QemuServer
::Monitor
qw(mon_cmd);
51 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr print_pcie_root_port);
52 use PVE
::QemuServer
::USB
qw(parse_usb_device);
56 require PVE
::Network
::SDN
::Zones
;
60 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
63 "$EDK2_FW_BASE/OVMF_CODE.fd",
64 "$EDK2_FW_BASE/OVMF_VARS.fd"
67 "$EDK2_FW_BASE/AAVMF_CODE.fd",
68 "$EDK2_FW_BASE/AAVMF_VARS.fd"
72 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
74 # Note about locking: we use flock on the config file protect
75 # against concurent actions.
76 # Aditionaly, we have a 'lock' setting in the config file. This
77 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
78 # allowed when such lock is set. But you can ignore this kind of
79 # lock with the --skiplock flag.
81 cfs_register_file
('/qemu-server/',
85 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
86 description
=> "Some command save/restore state from this location.",
92 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
93 description
=> "Specifies the Qemu machine type.",
95 pattern
=> '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
102 my ($map, $source) = @_;
104 return $source if !defined($map);
106 return $map->{entries
}->{$source}
107 if defined($map->{entries
}) && $map->{entries
}->{$source};
109 return $map->{default} if $map->{default};
111 # identity (fallback)
115 PVE
::JSONSchema
::register_standard_option
('pve-targetstorage', {
116 description
=> "Mapping from source to target storages. Providing only a single storage ID maps all source storages to that storage. Providing the special value '1' will map each source storage to itself.",
118 format
=> 'storagepair-list',
122 #no warnings 'redefine';
125 my ($controller, $vmid, $option, $value) = @_;
127 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
128 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
134 $nodename_cache //= PVE
::INotify
::nodename
();
135 return $nodename_cache;
142 enum
=> [qw(i6300esb ib700)],
143 description
=> "Watchdog type to emulate.",
144 default => 'i6300esb',
149 enum
=> [qw(reset shutdown poweroff pause debug none)],
150 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
154 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
158 description
=> "Enable/disable Qemu GuestAgent.",
163 fstrim_cloned_disks
=> {
164 description
=> "Run fstrim after cloning/moving a disk.",
170 description
=> "Select the agent type",
174 enum
=> [qw(virtio isa)],
180 description
=> "Select the VGA type.",
185 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
188 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
200 description
=> "The size of the file in MB.",
204 pattern
=> '[a-zA-Z0-9\-]+',
206 format_description
=> 'string',
207 description
=> "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
214 enum
=> [qw(ich9-intel-hda intel-hda AC97)],
215 description
=> "Configure an audio device."
222 description
=> "Driver backend for the audio device."
226 my $spice_enhancements_fmt = {
231 description
=> "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
235 enum
=> ['off', 'all', 'filter'],
238 description
=> "Enable video streaming. Uses compression for detected video streams."
245 enum
=> ['/dev/urandom', '/dev/random', '/dev/hwrng'],
247 description
=> "The file on the host to gather entropy from. In most"
248 . " cases /dev/urandom should be preferred over /dev/random"
249 . " to avoid entropy-starvation issues on the host. Using"
250 . " urandom does *not* decrease security in any meaningful"
251 . " way, as it's still seeded from real entropy, and the"
252 . " bytes provided will most likely be mixed with real"
253 . " entropy on the guest as well. /dev/hwrng can be used"
254 . " to pass through a hardware RNG from the host.",
258 description
=> "Maximum bytes of entropy injected into the guest every"
259 . " 'period' milliseconds. Prefer a lower value when using"
260 . " /dev/random as source. Use 0 to disable limiting"
261 . " (potentially dangerous!).",
264 # default is 1 KiB/s, provides enough entropy to the guest to avoid
265 # boot-starvation issues (e.g. systemd etc...) while allowing no chance
266 # of overwhelming the host, provided we're reading from /dev/urandom
271 description
=> "Every 'period' milliseconds the entropy-injection quota"
272 . " is reset, allowing the guest to retrieve another"
273 . " 'max_bytes' of entropy.",
283 description
=> "Specifies whether a VM will be started during system bootup.",
289 description
=> "Automatic restart after crash (currently ignored).",
294 type
=> 'string', format
=> 'pve-hotplug-features',
295 description
=> "Selectively enable hotplug features. This is a comma separated list of hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable hotplug completely. Value '1' is an alias for the default 'network,disk,usb'.",
296 default => 'network,disk,usb',
301 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
307 description
=> "Lock/unlock the VM.",
308 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
313 description
=> "Limit of CPU usage.",
314 verbose_description
=> "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has total of '2' CPU time. Value '0' indicates no CPU limit.",
322 description
=> "CPU weight for a VM.",
323 verbose_description
=> "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to weights of all the other running VMs.",
331 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
338 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
344 description
=> "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
352 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
353 "It should not be necessary to set it.",
354 enum
=> PVE
::Tools
::kvmkeymaplist
(),
359 type
=> 'string', format
=> 'dns-name',
360 description
=> "Set a name for the VM. Only used on the configuration web interface.",
365 description
=> "SCSI controller model",
366 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
372 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
377 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
378 description
=> "Specify guest operating system.",
379 verbose_description
=> <<EODESC,
380 Specify guest operating system. This is used to enable special
381 optimization/features for specific operating systems:
384 other;; unspecified OS
385 wxp;; Microsoft Windows XP
386 w2k;; Microsoft Windows 2000
387 w2k3;; Microsoft Windows 2003
388 w2k8;; Microsoft Windows 2008
389 wvista;; Microsoft Windows Vista
390 win7;; Microsoft Windows 7
391 win8;; Microsoft Windows 8/2012/2012r2
392 win10;; Microsoft Windows 10/2016
393 l24;; Linux 2.4 Kernel
394 l26;; Linux 2.6 - 5.X Kernel
395 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
401 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
402 pattern
=> '[acdn]{1,4}',
407 type
=> 'string', format
=> 'pve-qm-bootdisk',
408 description
=> "Enable booting from specified disk.",
409 pattern
=> '(ide|sata|scsi|virtio)\d+',
414 description
=> "The number of CPUs. Please use option -sockets instead.",
421 description
=> "The number of CPU sockets.",
428 description
=> "The number of cores per socket.",
435 description
=> "Enable/disable NUMA.",
441 description
=> "Enable/disable hugepages memory.",
442 enum
=> [qw(any 2 1024)],
447 description
=> "Number of hotplugged vcpus.",
454 description
=> "Enable/disable ACPI.",
459 description
=> "Enable/disable Qemu GuestAgent and its properties.",
461 format
=> $agent_fmt,
466 description
=> "Enable/disable KVM hardware virtualization.",
472 description
=> "Enable/disable time drift fix.",
478 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
483 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
487 type
=> 'string', format
=> $vga_fmt,
488 description
=> "Configure the VGA hardware.",
489 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
490 "high resolution modes (>= 1280x1024x16) you may need to increase " .
491 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
492 "is 'std' for all OS types besides some Windows versions (XP and " .
493 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
494 "display server. For win* OS you can select how many independent " .
495 "displays you want, Linux guests can add displays them self.\n".
496 "You can also run without any graphic card, using a serial device as terminal.",
500 type
=> 'string', format
=> 'pve-qm-watchdog',
501 description
=> "Create a virtual hardware watchdog device.",
502 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
503 " (by a guest action), the watchdog must be periodically polled " .
504 "by an agent inside the guest or else the watchdog will reset " .
505 "the guest (or execute the respective action specified)",
510 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
511 description
=> "Set the initial date of the real time clock. Valid format for date are: 'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
512 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
515 startup
=> get_standard_option
('pve-startup-order'),
519 description
=> "Enable/disable Template.",
525 description
=> "Arbitrary arguments passed to kvm.",
526 verbose_description
=> <<EODESCR,
527 Arbitrary arguments passed to kvm, for example:
529 args: -no-reboot -no-hpet
531 NOTE: this option is for experts only.
538 description
=> "Enable/disable the USB tablet device.",
539 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
540 "usually needed to allow absolute mouse positioning with VNC. " .
541 "Else the mouse runs out of sync with normal VNC clients. " .
542 "If you're running lots of console-only guests on one host, " .
543 "you may consider disabling this to save some context switches. " .
544 "This is turned off by default if you use spice (-vga=qxl).",
549 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
553 migrate_downtime
=> {
556 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
562 type
=> 'string', format
=> 'pve-qm-ide',
563 typetext
=> '<volume>',
564 description
=> "This is an alias for option -ide2",
568 description
=> "Emulated CPU type.",
570 format
=> 'pve-vm-cpu-conf',
572 parent
=> get_standard_option
('pve-snapshot-name', {
574 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
578 description
=> "Timestamp for snapshots.",
584 type
=> 'string', format
=> 'pve-volume-id',
585 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
587 vmstatestorage
=> get_standard_option
('pve-storage-id', {
588 description
=> "Default storage for VM state volumes/files.",
591 runningmachine
=> get_standard_option
('pve-qemu-machine', {
592 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
594 machine
=> get_standard_option
('pve-qemu-machine'),
596 description
=> "Virtual processor architecture. Defaults to the host.",
599 enum
=> [qw(x86_64 aarch64)],
602 description
=> "Specify SMBIOS type 1 fields.",
603 type
=> 'string', format
=> 'pve-qm-smbios1',
610 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
616 enum
=> [ qw(seabios ovmf) ],
617 description
=> "Select BIOS implementation.",
618 default => 'seabios',
622 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
623 format_description
=> 'UUID',
624 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
625 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
626 " 128-bit integer value identifier to the guest OS. This allows to".
627 " notify the guest operating system when the virtual machine is".
628 " executed with a different configuration (e.g. snapshot execution".
629 " or creation from a template). The guest operating system notices".
630 " the change, and is then able to react as appropriate by marking".
631 " its copies of distributed databases as dirty, re-initializing its".
632 " random number generator, etc.\n".
633 "Note that auto-creation only works when done throug API/CLI create".
634 " or update methods, but not when manually editing the config file.",
635 default => "1 (autogenerated)",
640 format
=> 'pve-volume-id',
642 description
=> "Script that will be executed during various steps in the vms lifetime.",
646 format
=> $ivshmem_fmt,
647 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to the host.",
652 format
=> $audio_fmt,
653 description
=> "Configure a audio device, useful in combination with QXL/Spice.",
656 spice_enhancements
=> {
658 format
=> $spice_enhancements_fmt,
659 description
=> "Configure additional enhancements for SPICE.",
663 type
=> 'string', format
=> 'pve-tag-list',
664 description
=> 'Tags of the VM. This is only meta information.',
670 description
=> "Configure a VirtIO-based Random Number Generator.",
679 description
=> 'Specify a custom file containing all meta data passed to the VM via cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
680 format
=> 'pve-volume-id',
681 format_description
=> 'volume',
686 description
=> 'Specify a custom file containing all network data passed to the VM via cloud-init.',
687 format
=> 'pve-volume-id',
688 format_description
=> 'volume',
693 description
=> 'Specify a custom file containing all user data passed to the VM via cloud-init.',
694 format
=> 'pve-volume-id',
695 format_description
=> 'volume',
698 PVE
::JSONSchema
::register_format
('pve-qm-cicustom', $cicustom_fmt);
700 my $confdesc_cloudinit = {
704 description
=> 'Specifies the cloud-init configuration format. The default depends on the configured operating system type (`ostype`. We use the `nocloud` format for Linux, and `configdrive2` for windows.',
705 enum
=> ['configdrive2', 'nocloud'],
710 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
715 description
=> 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
720 description
=> 'cloud-init: Specify custom files to replace the automatically generated ones at start.',
721 format
=> 'pve-qm-cicustom',
726 description
=> "cloud-init: Sets DNS search domains for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
730 type
=> 'string', format
=> 'address-list',
731 description
=> "cloud-init: Sets DNS server IP address for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
736 format
=> 'urlencoded',
737 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
741 # what about other qemu settings ?
743 #machine => 'string',
756 ##soundhw => 'string',
758 while (my ($k, $v) = each %$confdesc) {
759 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
762 my $MAX_USB_DEVICES = 5;
764 my $MAX_HOSTPCI_DEVICES = 16;
765 my $MAX_SERIAL_PORTS = 4;
766 my $MAX_PARALLEL_PORTS = 3;
772 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
773 description
=> "CPUs accessing this NUMA node.",
774 format_description
=> "id[-id];...",
778 description
=> "Amount of memory this NUMA node provides.",
783 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
784 description
=> "Host NUMA nodes to use.",
785 format_description
=> "id[-id];...",
790 enum
=> [qw(preferred bind interleave)],
791 description
=> "NUMA allocation policy.",
795 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
798 type
=> 'string', format
=> $numa_fmt,
799 description
=> "NUMA topology.",
801 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
803 for (my $i = 0; $i < $MAX_NUMA; $i++) {
804 $confdesc->{"numa$i"} = $numadesc;
807 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
808 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
809 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
810 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
812 my $net_fmt_bridge_descr = <<__EOD__;
813 Bridge to attach the network device to. The Proxmox VE standard bridge
816 If you do not specify a bridge, we create a kvm user (NATed) network
817 device, which provides DHCP and DNS services. The following addresses
824 The DHCP server assign addresses to the guest starting from 10.0.2.15.
828 macaddr
=> get_standard_option
('mac-addr', {
829 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
833 description
=> "Network Card Model. The 'virtio' model provides the best performance with very low CPU overhead. If your guest does not support this driver, it is usually best to use 'e1000'.",
834 enum
=> $nic_model_list,
837 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
840 description
=> $net_fmt_bridge_descr,
841 format_description
=> 'bridge',
846 minimum
=> 0, maximum
=> 16,
847 description
=> 'Number of packet queues to be used on the device.',
853 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
858 minimum
=> 1, maximum
=> 4094,
859 description
=> 'VLAN tag to apply to packets on this interface.',
864 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
865 description
=> 'VLAN trunks to pass through this interface.',
866 format_description
=> 'vlanid[;vlanid...]',
871 description
=> 'Whether this interface should be protected by the firewall.',
876 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
883 type
=> 'string', format
=> $net_fmt,
884 description
=> "Specify network devices.",
887 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
892 format
=> 'pve-ipv4-config',
893 format_description
=> 'IPv4Format/CIDR',
894 description
=> 'IPv4 address in CIDR format.',
901 format_description
=> 'GatewayIPv4',
902 description
=> 'Default gateway for IPv4 traffic.',
908 format
=> 'pve-ipv6-config',
909 format_description
=> 'IPv6Format/CIDR',
910 description
=> 'IPv6 address in CIDR format.',
917 format_description
=> 'GatewayIPv6',
918 description
=> 'Default gateway for IPv6 traffic.',
923 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
926 type
=> 'string', format
=> 'pve-qm-ipconfig',
927 description
=> <<'EODESCR',
928 cloud-init: Specify IP addresses and gateways for the corresponding interface.
930 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
932 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
933 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
935 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
938 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
940 for (my $i = 0; $i < $MAX_NETS; $i++) {
941 $confdesc->{"net$i"} = $netdesc;
942 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
945 foreach my $key (keys %$confdesc_cloudinit) {
946 $confdesc->{$key} = $confdesc_cloudinit->{$key};
949 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
950 sub verify_volume_id_or_qm_path
{
951 my ($volid, $noerr) = @_;
953 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
957 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
958 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
960 return undef if $noerr;
969 type
=> 'string', format
=> 'pve-qm-usb-device',
970 format_description
=> 'HOSTUSBDEVICE|spice',
971 description
=> <<EODESCR,
972 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
974 'bus-port(.port)*' (decimal numbers) or
975 'vendor_id:product_id' (hexadeciaml numbers) or
978 You can use the 'lsusb -t' command to list existing usb devices.
980 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
982 The value 'spice' can be used to add a usb redirection devices for spice.
988 description
=> "Specifies whether if given host option is a USB3 device or port.",
995 type
=> 'string', format
=> $usb_fmt,
996 description
=> "Configure an USB device (n is 0 to 4).",
998 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1000 my $PCIRE = qr/([a-f0-9]{4}:)?[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
1005 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1006 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1007 description
=> <<EODESCR,
1008 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1009 of PCI virtual functions of the host. HOSTPCIID syntax is:
1011 'bus:dev.func' (hexadecimal numbers)
1013 You can us the 'lspci' command to list existing PCI devices.
1018 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1024 pattern
=> '[^,;]+',
1025 format_description
=> 'string',
1026 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1031 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1037 description
=> "Enable vfio-vga device support.",
1043 format_description
=> 'string',
1044 pattern
=> '[^/\.:]+',
1046 description
=> <<EODESCR
1047 The type of mediated device to use.
1048 An instance of this type will be created on startup of the VM and
1049 will be cleaned up when the VM stops.
1053 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1057 type
=> 'string', format
=> 'pve-qm-hostpci',
1058 description
=> "Map host PCI devices into guest.",
1059 verbose_description
=> <<EODESCR,
1060 Map host PCI devices into guest.
1062 NOTE: This option allows direct access to host hardware. So it is no longer
1063 possible to migrate such machines - use with special care.
1065 CAUTION: Experimental! User reported problems with this option.
1068 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1073 pattern
=> '(/dev/.+|socket)',
1074 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1075 verbose_description
=> <<EODESCR,
1076 Create a serial device inside the VM (n is 0 to 3), and pass through a
1077 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1078 host side (use 'qm terminal' to open a terminal connection).
1080 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1082 CAUTION: Experimental! User reported problems with this option.
1089 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1090 description
=> "Map host parallel devices (n is 0 to 2).",
1091 verbose_description
=> <<EODESCR,
1092 Map host parallel devices (n is 0 to 2).
1094 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1096 CAUTION: Experimental! User reported problems with this option.
1100 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1101 $confdesc->{"parallel$i"} = $paralleldesc;
1104 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1105 $confdesc->{"serial$i"} = $serialdesc;
1108 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1109 $confdesc->{"hostpci$i"} = $hostpcidesc;
1112 for my $key (keys %{$PVE::QemuServer
::Drive
::drivedesc_hash
}) {
1113 $confdesc->{$key} = $PVE::QemuServer
::Drive
::drivedesc_hash-
>{$key};
1116 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1117 $confdesc->{"usb$i"} = $usbdesc;
1120 my $kvm_api_version = 0;
1123 return $kvm_api_version if $kvm_api_version;
1125 open my $fh, '<', '/dev/kvm'
1128 # 0xae00 => KVM_GET_API_VERSION
1129 $kvm_api_version = ioctl($fh, 0xae00, 0);
1131 return $kvm_api_version;
1134 my $kvm_user_version = {};
1137 sub kvm_user_version
{
1140 $binary //= get_command_for_arch
(get_host_arch
()); # get the native arch by default
1141 my $st = stat($binary);
1143 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1144 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1145 $cachedmtime == $st->mtime;
1147 $kvm_user_version->{$binary} = 'unknown';
1148 $kvm_mtime->{$binary} = $st->mtime;
1152 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1153 $kvm_user_version->{$binary} = $2;
1157 eval { run_command
([$binary, '--version'], outfunc
=> $code); };
1160 return $kvm_user_version->{$binary};
1164 sub kernel_has_vhost_net
{
1165 return -c
'/dev/vhost-net';
1170 return defined($confdesc->{$key});
1174 sub get_cdrom_path
{
1176 return $cdrom_path if $cdrom_path;
1178 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1179 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1180 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1184 my ($storecfg, $vmid, $cdrom) = @_;
1186 if ($cdrom eq 'cdrom') {
1187 return get_cdrom_path
();
1188 } elsif ($cdrom eq 'none') {
1190 } elsif ($cdrom =~ m
|^/|) {
1193 return PVE
::Storage
::path
($storecfg, $cdrom);
1197 # try to convert old style file names to volume IDs
1198 sub filename_to_volume_id
{
1199 my ($vmid, $file, $media) = @_;
1201 if (!($file eq 'none' || $file eq 'cdrom' ||
1202 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1204 return undef if $file =~ m
|/|;
1206 if ($media && $media eq 'cdrom') {
1207 $file = "local:iso/$file";
1209 $file = "local:$vmid/$file";
1216 sub verify_media_type
{
1217 my ($opt, $vtype, $media) = @_;
1222 if ($media eq 'disk') {
1224 } elsif ($media eq 'cdrom') {
1227 die "internal error";
1230 return if ($vtype eq $etype);
1232 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1235 sub cleanup_drive_path
{
1236 my ($opt, $storecfg, $drive) = @_;
1238 # try to convert filesystem paths to volume IDs
1240 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1241 ($drive->{file
} !~ m
|^/dev/.+|) &&
1242 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1243 ($drive->{file
} !~ m/^\d+$/)) {
1244 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1245 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1246 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1247 verify_media_type
($opt, $vtype, $drive->{media
});
1248 $drive->{file
} = $volid;
1251 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1254 sub parse_hotplug_features
{
1259 return $res if $data eq '0';
1261 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1263 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1264 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1267 die "invalid hotplug feature '$feature'\n";
1273 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1274 sub pve_verify_hotplug_features
{
1275 my ($value, $noerr) = @_;
1277 return $value if parse_hotplug_features
($value);
1279 return undef if $noerr;
1281 die "unable to parse hotplug option\n";
1285 my($fh, $noerr) = @_;
1288 my $SG_GET_VERSION_NUM = 0x2282;
1290 my $versionbuf = "\x00" x
8;
1291 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1293 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1296 my $version = unpack("I", $versionbuf);
1297 if ($version < 30000) {
1298 die "scsi generic interface too old\n" if !$noerr;
1302 my $buf = "\x00" x
36;
1303 my $sensebuf = "\x00" x
8;
1304 my $cmd = pack("C x3 C x1", 0x12, 36);
1306 # see /usr/include/scsi/sg.h
1307 my $sg_io_hdr_t = "i i C C s I P P P I I i P C C C C S S i I I";
1309 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1310 length($sensebuf), 0, length($buf), $buf,
1311 $cmd, $sensebuf, 6000);
1313 $ret = ioctl($fh, $SG_IO, $packet);
1315 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1319 my @res = unpack($sg_io_hdr_t, $packet);
1320 if ($res[17] || $res[18]) {
1321 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1326 (my $byte0, my $byte1, $res->{vendor
},
1327 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1329 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1330 $res->{type
} = $byte0 & 31;
1338 my $fh = IO
::File-
>new("+<$path") || return undef;
1339 my $res = scsi_inquiry
($fh, 1);
1345 sub print_tabletdevice_full
{
1346 my ($conf, $arch) = @_;
1348 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1350 # we use uhci for old VMs because tablet driver was buggy in older qemu
1352 if (PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1358 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1361 sub print_keyboarddevice_full
{
1362 my ($conf, $arch, $machine) = @_;
1364 return undef if $arch ne 'aarch64';
1366 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1369 sub print_drivedevice_full
{
1370 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1375 if ($drive->{interface
} eq 'virtio') {
1376 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1377 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1378 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1379 } elsif ($drive->{interface
} eq 'scsi') {
1381 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1382 my $unit = $drive->{index} % $maxdev;
1383 my $devicetype = 'hd';
1385 if (drive_is_cdrom
($drive)) {
1388 if ($drive->{file
} =~ m
|^/|) {
1389 $path = $drive->{file
};
1390 if (my $info = path_is_scsi
($path)) {
1391 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1392 $devicetype = 'block';
1393 } elsif ($info->{type
} == 1) { # tape
1394 $devicetype = 'generic';
1398 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1401 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
1402 my $version = PVE
::QemuServer
::Machine
::extract_version
($machine_type, kvm_user_version
());
1403 if ($path =~ m/^iscsi\:\/\
// &&
1404 !min_version
($version, 4, 1)) {
1405 $devicetype = 'generic';
1409 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1410 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1412 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0,lun=$drive->{index},drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1415 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1416 $device .= ",rotation_rate=1";
1418 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1420 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1421 my $maxdev = ($drive->{interface
} eq 'sata') ?
$PVE::QemuServer
::Drive
::MAX_SATA_DISKS
: 2;
1422 my $controller = int($drive->{index} / $maxdev);
1423 my $unit = $drive->{index} % $maxdev;
1424 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1426 $device = "ide-$devicetype";
1427 if ($drive->{interface
} eq 'ide') {
1428 $device .= ",bus=ide.$controller,unit=$unit";
1430 $device .= ",bus=ahci$controller.$unit";
1432 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1434 if ($devicetype eq 'hd') {
1435 if (my $model = $drive->{model
}) {
1436 $model = URI
::Escape
::uri_unescape
($model);
1437 $device .= ",model=$model";
1439 if ($drive->{ssd
}) {
1440 $device .= ",rotation_rate=1";
1443 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1444 } elsif ($drive->{interface
} eq 'usb') {
1446 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1448 die "unsupported interface type";
1451 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1453 if (my $serial = $drive->{serial
}) {
1454 $serial = URI
::Escape
::uri_unescape
($serial);
1455 $device .= ",serial=$serial";
1462 sub get_initiator_name
{
1465 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1466 while (defined(my $line = <$fh>)) {
1467 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1476 sub print_drive_commandline_full
{
1477 my ($storecfg, $vmid, $drive) = @_;
1480 my $volid = $drive->{file
};
1483 if (drive_is_cdrom
($drive)) {
1484 $path = get_iso_path
($storecfg, $vmid, $volid);
1486 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1488 $path = PVE
::Storage
::path
($storecfg, $volid);
1489 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1490 $format = qemu_img_format
($scfg, $volname);
1498 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1499 foreach my $o (@qemu_drive_options) {
1500 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1503 # snapshot only accepts on|off
1504 if (defined($drive->{snapshot
})) {
1505 my $v = $drive->{snapshot
} ?
'on' : 'off';
1506 $opts .= ",snapshot=$v";
1509 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1510 my ($dir, $qmpname) = @$type;
1511 if (my $v = $drive->{"mbps$dir"}) {
1512 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1514 if (my $v = $drive->{"mbps${dir}_max"}) {
1515 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1517 if (my $v = $drive->{"bps${dir}_max_length"}) {
1518 $opts .= ",throttling.bps$qmpname-max-length=$v";
1520 if (my $v = $drive->{"iops${dir}"}) {
1521 $opts .= ",throttling.iops$qmpname=$v";
1523 if (my $v = $drive->{"iops${dir}_max"}) {
1524 $opts .= ",throttling.iops$qmpname-max=$v";
1526 if (my $v = $drive->{"iops${dir}_max_length"}) {
1527 $opts .= ",throttling.iops$qmpname-max-length=$v";
1531 $opts .= ",format=$format" if $format && !$drive->{format
};
1533 my $cache_direct = 0;
1535 if (my $cache = $drive->{cache
}) {
1536 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1537 } elsif (!drive_is_cdrom
($drive)) {
1538 $opts .= ",cache=none";
1542 # aio native works only with O_DIRECT
1543 if (!$drive->{aio
}) {
1545 $opts .= ",aio=native";
1547 $opts .= ",aio=threads";
1551 if (!drive_is_cdrom
($drive)) {
1553 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1554 $detectzeroes = 'off';
1555 } elsif ($drive->{discard
}) {
1556 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1558 # This used to be our default with discard not being specified:
1559 $detectzeroes = 'on';
1561 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1564 my $pathinfo = $path ?
"file=$path," : '';
1566 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1569 sub print_netdevice_full
{
1570 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1572 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1574 my $device = $net->{model
};
1575 if ($net->{model
} eq 'virtio') {
1576 $device = 'virtio-net-pci';
1579 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1580 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1581 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1582 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1583 my $vectors = $net->{queues
} * 2 + 2;
1584 $tmpstr .= ",vectors=$vectors,mq=on";
1586 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1588 if ($use_old_bios_files) {
1590 if ($device eq 'virtio-net-pci') {
1591 $romfile = 'pxe-virtio.rom';
1592 } elsif ($device eq 'e1000') {
1593 $romfile = 'pxe-e1000.rom';
1594 } elsif ($device eq 'ne2k') {
1595 $romfile = 'pxe-ne2k_pci.rom';
1596 } elsif ($device eq 'pcnet') {
1597 $romfile = 'pxe-pcnet.rom';
1598 } elsif ($device eq 'rtl8139') {
1599 $romfile = 'pxe-rtl8139.rom';
1601 $tmpstr .= ",romfile=$romfile" if $romfile;
1607 sub print_netdev_full
{
1608 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1611 if ($netid =~ m/^net(\d+)$/) {
1615 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1617 my $ifname = "tap${vmid}i$i";
1619 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1620 die "interface name '$ifname' is too long (max 15 character)\n"
1621 if length($ifname) >= 16;
1623 my $vhostparam = '';
1624 if (is_native
($arch)) {
1625 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
1628 my $vmname = $conf->{name
} || "vm$vmid";
1631 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1633 if ($net->{bridge
}) {
1634 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1636 $netdev = "type=user,id=$netid,hostname=$vmname";
1639 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1645 'cirrus' => 'cirrus-vga',
1647 'vmware' => 'vmware-svga',
1648 'virtio' => 'virtio-vga',
1651 sub print_vga_device
{
1652 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
1654 my $type = $vga_map->{$vga->{type
}};
1655 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
1656 $type = 'virtio-gpu';
1658 my $vgamem_mb = $vga->{memory
};
1660 my $max_outputs = '';
1662 $type = $id ?
'qxl' : 'qxl-vga';
1664 if (!$conf->{ostype
} || $conf->{ostype
} =~ m/^(?:l\d\d)|(?:other)$/) {
1665 # set max outputs so linux can have up to 4 qxl displays with one device
1666 if (min_version
($machine_version, 4, 1)) {
1667 $max_outputs = ",max_outputs=4";
1672 die "no devicetype for $vga->{type}\n" if !$type;
1676 if ($vga->{type
} eq 'virtio') {
1677 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
1678 $memory = ",max_hostmem=$bytes";
1680 # from https://www.spice-space.org/multiple-monitors.html
1681 $memory = ",vgamem_mb=$vga->{memory}";
1682 my $ram = $vgamem_mb * 4;
1683 my $vram = $vgamem_mb * 2;
1684 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1686 $memory = ",vgamem_mb=$vga->{memory}";
1688 } elsif ($qxlnum && $id) {
1689 $memory = ",ram_size=67108864,vram_size=33554432";
1692 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1693 my $vgaid = "vga" . ($id // '');
1696 if ($q35 && $vgaid eq 'vga') {
1697 # the first display uses pcie.0 bus on q35 machines
1698 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
1700 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
1703 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}";
1706 sub parse_number_sets
{
1709 foreach my $part (split(/;/, $set)) {
1710 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1711 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1712 push @$res, [ $1, $2 ];
1714 die "invalid range: $part\n";
1723 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1724 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1725 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1732 return undef if !$value;
1734 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1736 my @idlist = split(/;/, $res->{host
});
1737 delete $res->{host
};
1738 foreach my $id (@idlist) {
1739 my $devs = PVE
::SysFSTools
::lspci
($id);
1740 die "no PCI device found for '$id'\n" if !scalar(@$devs);
1741 push @{$res->{pciid
}}, @$devs;
1746 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1750 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1755 if (!defined($res->{macaddr
})) {
1756 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1757 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1762 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1763 sub parse_ipconfig
{
1766 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1772 if ($res->{gw
} && !$res->{ip
}) {
1773 warn 'gateway specified without specifying an IP address';
1776 if ($res->{gw6
} && !$res->{ip6
}) {
1777 warn 'IPv6 gateway specified without specifying an IPv6 address';
1780 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1781 warn 'gateway specified together with DHCP';
1784 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1786 warn "IPv6 gateway specified together with $res->{ip6} address";
1790 if (!$res->{ip
} && !$res->{ip6
}) {
1791 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1800 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1803 sub add_random_macs
{
1804 my ($settings) = @_;
1806 foreach my $opt (keys %$settings) {
1807 next if $opt !~ m/^net(\d+)$/;
1808 my $net = parse_net
($settings->{$opt});
1810 $settings->{$opt} = print_net
($net);
1814 sub vm_is_volid_owner
{
1815 my ($storecfg, $vmid, $volid) = @_;
1817 if ($volid !~ m
|^/|) {
1819 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1820 if ($owner && ($owner == $vmid)) {
1828 sub vmconfig_register_unused_drive
{
1829 my ($storecfg, $vmid, $conf, $drive) = @_;
1831 if (drive_is_cloudinit
($drive)) {
1832 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
1834 } elsif (!drive_is_cdrom
($drive)) {
1835 my $volid = $drive->{file
};
1836 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1837 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1842 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
1846 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1847 format_description
=> 'UUID',
1848 description
=> "Set SMBIOS1 UUID.",
1853 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1854 format_description
=> 'Base64 encoded string',
1855 description
=> "Set SMBIOS1 version.",
1860 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1861 format_description
=> 'Base64 encoded string',
1862 description
=> "Set SMBIOS1 serial number.",
1867 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1868 format_description
=> 'Base64 encoded string',
1869 description
=> "Set SMBIOS1 manufacturer.",
1874 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1875 format_description
=> 'Base64 encoded string',
1876 description
=> "Set SMBIOS1 product ID.",
1881 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1882 format_description
=> 'Base64 encoded string',
1883 description
=> "Set SMBIOS1 SKU string.",
1888 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1889 format_description
=> 'Base64 encoded string',
1890 description
=> "Set SMBIOS1 family string.",
1895 description
=> 'Flag to indicate that the SMBIOS values are base64 encoded',
1903 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
1910 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
1913 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
1915 sub parse_watchdog
{
1918 return undef if !$value;
1920 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
1925 sub parse_guest_agent
{
1928 return {} if !defined($value->{agent
});
1930 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
1933 # if the agent is disabled ignore the other potentially set properties
1934 return {} if !$res->{enabled
};
1941 return {} if !$value;
1942 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
1950 return undef if !$value;
1952 my $res = eval { PVE
::JSONSchema
::parse_property_string
($rng_fmt, $value) };
1957 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
1958 sub verify_usb_device
{
1959 my ($value, $noerr) = @_;
1961 return $value if parse_usb_device
($value);
1963 return undef if $noerr;
1965 die "unable to parse usb device\n";
1968 # add JSON properties for create and set function
1969 sub json_config_properties
{
1972 foreach my $opt (keys %$confdesc) {
1973 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
1974 $prop->{$opt} = $confdesc->{$opt};
1980 # return copy of $confdesc_cloudinit to generate documentation
1981 sub cloudinit_config_properties
{
1983 return dclone
($confdesc_cloudinit);
1987 my ($key, $value) = @_;
1989 die "unknown setting '$key'\n" if !$confdesc->{$key};
1991 my $type = $confdesc->{$key}->{type
};
1993 if (!defined($value)) {
1994 die "got undefined value\n";
1997 if ($value =~ m/[\n\r]/) {
1998 die "property contains a line feed\n";
2001 if ($type eq 'boolean') {
2002 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2003 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2004 die "type check ('boolean') failed - got '$value'\n";
2005 } elsif ($type eq 'integer') {
2006 return int($1) if $value =~ m/^(\d+)$/;
2007 die "type check ('integer') failed - got '$value'\n";
2008 } elsif ($type eq 'number') {
2009 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2010 die "type check ('number') failed - got '$value'\n";
2011 } elsif ($type eq 'string') {
2012 if (my $fmt = $confdesc->{$key}->{format
}) {
2013 PVE
::JSONSchema
::check_format
($fmt, $value);
2016 $value =~ s/^\"(.*)\"$/$1/;
2019 die "internal error"
2024 my ($storecfg, $vmid, $skiplock, $replacement_conf) = @_;
2026 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2028 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2030 if ($conf->{template
}) {
2031 # check if any base image is still used by a linked clone
2032 foreach_drive
($conf, sub {
2033 my ($ds, $drive) = @_;
2034 return if drive_is_cdrom
($drive);
2036 my $volid = $drive->{file
};
2037 return if !$volid || $volid =~ m
|^/|;
2039 die "base volume '$volid' is still in use by linked cloned\n"
2040 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2045 # only remove disks owned by this VM
2046 foreach_drive
($conf, sub {
2047 my ($ds, $drive) = @_;
2048 return if drive_is_cdrom
($drive, 1);
2050 my $volid = $drive->{file
};
2051 return if !$volid || $volid =~ m
|^/|;
2053 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2054 return if !$path || !$owner || ($owner != $vmid);
2056 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2057 warn "Could not remove disk '$volid', check manually: $@" if $@;
2060 # also remove unused disk
2061 my $vmdisks = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2062 PVE
::Storage
::foreach_volid
($vmdisks, sub {
2063 my ($volid, $sid, $volname, $d) = @_;
2064 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2068 if (defined $replacement_conf) {
2069 PVE
::QemuConfig-
>write_config($vmid, $replacement_conf);
2071 PVE
::QemuConfig-
>destroy_config($vmid);
2075 sub parse_vm_config
{
2076 my ($filename, $raw) = @_;
2078 return undef if !defined($raw);
2081 digest
=> Digest
::SHA
::sha1_hex
($raw),
2086 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2087 || die "got strange filename '$filename'";
2095 my @lines = split(/\n/, $raw);
2096 foreach my $line (@lines) {
2097 next if $line =~ m/^\s*$/;
2099 if ($line =~ m/^\[PENDING\]\s*$/i) {
2100 $section = 'pending';
2101 if (defined($descr)) {
2103 $conf->{description
} = $descr;
2106 $conf = $res->{$section} = {};
2109 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2111 if (defined($descr)) {
2113 $conf->{description
} = $descr;
2116 $conf = $res->{snapshots
}->{$section} = {};
2120 if ($line =~ m/^\#(.*)\s*$/) {
2121 $descr = '' if !defined($descr);
2122 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2126 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2127 $descr = '' if !defined($descr);
2128 $descr .= PVE
::Tools
::decode_text
($2);
2129 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2130 $conf->{snapstate
} = $1;
2131 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2134 $conf->{$key} = $value;
2135 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2137 if ($section eq 'pending') {
2138 $conf->{delete} = $value; # we parse this later
2140 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2142 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2145 eval { $value = check_type
($key, $value); };
2147 warn "vm $vmid - unable to parse value of '$key' - $@";
2149 $key = 'ide2' if $key eq 'cdrom';
2150 my $fmt = $confdesc->{$key}->{format
};
2151 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2152 my $v = parse_drive
($key, $value);
2153 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2154 $v->{file
} = $volid;
2155 $value = print_drive
($v);
2157 warn "vm $vmid - unable to parse value of '$key'\n";
2162 $conf->{$key} = $value;
2167 if (defined($descr)) {
2169 $conf->{description
} = $descr;
2171 delete $res->{snapstate
}; # just to be sure
2176 sub write_vm_config
{
2177 my ($filename, $conf) = @_;
2179 delete $conf->{snapstate
}; # just to be sure
2181 if ($conf->{cdrom
}) {
2182 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2183 $conf->{ide2
} = $conf->{cdrom
};
2184 delete $conf->{cdrom
};
2187 # we do not use 'smp' any longer
2188 if ($conf->{sockets
}) {
2189 delete $conf->{smp
};
2190 } elsif ($conf->{smp
}) {
2191 $conf->{sockets
} = $conf->{smp
};
2192 delete $conf->{cores
};
2193 delete $conf->{smp
};
2196 my $used_volids = {};
2198 my $cleanup_config = sub {
2199 my ($cref, $pending, $snapname) = @_;
2201 foreach my $key (keys %$cref) {
2202 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2203 $key eq 'snapstate' || $key eq 'pending';
2204 my $value = $cref->{$key};
2205 if ($key eq 'delete') {
2206 die "propertry 'delete' is only allowed in [PENDING]\n"
2208 # fixme: check syntax?
2211 eval { $value = check_type
($key, $value); };
2212 die "unable to parse value of '$key' - $@" if $@;
2214 $cref->{$key} = $value;
2216 if (!$snapname && is_valid_drivename
($key)) {
2217 my $drive = parse_drive
($key, $value);
2218 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2223 &$cleanup_config($conf);
2225 &$cleanup_config($conf->{pending
}, 1);
2227 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2228 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
2229 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2232 # remove 'unusedX' settings if we re-add a volume
2233 foreach my $key (keys %$conf) {
2234 my $value = $conf->{$key};
2235 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2236 delete $conf->{$key};
2240 my $generate_raw_config = sub {
2241 my ($conf, $pending) = @_;
2245 # add description as comment to top of file
2246 if (defined(my $descr = $conf->{description
})) {
2248 foreach my $cl (split(/\n/, $descr)) {
2249 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2252 $raw .= "#\n" if $pending;
2256 foreach my $key (sort keys %$conf) {
2257 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2258 $raw .= "$key: $conf->{$key}\n";
2263 my $raw = &$generate_raw_config($conf);
2265 if (scalar(keys %{$conf->{pending
}})){
2266 $raw .= "\n[PENDING]\n";
2267 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2270 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2271 $raw .= "\n[$snapname]\n";
2272 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2282 # we use static defaults from our JSON schema configuration
2283 foreach my $key (keys %$confdesc) {
2284 if (defined(my $default = $confdesc->{$key}->{default})) {
2285 $res->{$key} = $default;
2293 my $vmlist = PVE
::Cluster
::get_vmlist
();
2295 return $res if !$vmlist || !$vmlist->{ids
};
2296 my $ids = $vmlist->{ids
};
2297 my $nodename = nodename
();
2299 foreach my $vmid (keys %$ids) {
2300 my $d = $ids->{$vmid};
2301 next if !$d->{node
} || $d->{node
} ne $nodename;
2302 next if !$d->{type
} || $d->{type
} ne 'qemu';
2303 $res->{$vmid}->{exists} = 1;
2308 # test if VM uses local resources (to prevent migration)
2309 sub check_local_resources
{
2310 my ($conf, $noerr) = @_;
2314 push @loc_res, "hostusb" if $conf->{hostusb
}; # old syntax
2315 push @loc_res, "hostpci" if $conf->{hostpci
}; # old syntax
2317 push @loc_res, "ivshmem" if $conf->{ivshmem
};
2319 foreach my $k (keys %$conf) {
2320 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
2321 # sockets are safe: they will recreated be on the target side post-migrate
2322 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2323 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2326 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
2331 # check if used storages are available on all nodes (use by migrate)
2332 sub check_storage_availability
{
2333 my ($storecfg, $conf, $node) = @_;
2335 foreach_drive
($conf, sub {
2336 my ($ds, $drive) = @_;
2338 my $volid = $drive->{file
};
2341 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2344 # check if storage is available on both nodes
2345 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2346 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2350 # list nodes where all VM images are available (used by has_feature API)
2352 my ($conf, $storecfg) = @_;
2354 my $nodelist = PVE
::Cluster
::get_nodelist
();
2355 my $nodehash = { map { $_ => 1 } @$nodelist };
2356 my $nodename = nodename
();
2358 foreach_drive
($conf, sub {
2359 my ($ds, $drive) = @_;
2361 my $volid = $drive->{file
};
2364 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2366 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2367 if ($scfg->{disable
}) {
2369 } elsif (my $avail = $scfg->{nodes
}) {
2370 foreach my $node (keys %$nodehash) {
2371 delete $nodehash->{$node} if !$avail->{$node};
2373 } elsif (!$scfg->{shared
}) {
2374 foreach my $node (keys %$nodehash) {
2375 delete $nodehash->{$node} if $node ne $nodename
2384 sub check_local_storage_availability
{
2385 my ($conf, $storecfg) = @_;
2387 my $nodelist = PVE
::Cluster
::get_nodelist
();
2388 my $nodehash = { map { $_ => {} } @$nodelist };
2390 foreach_drive
($conf, sub {
2391 my ($ds, $drive) = @_;
2393 my $volid = $drive->{file
};
2396 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2398 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2400 if ($scfg->{disable
}) {
2401 foreach my $node (keys %$nodehash) {
2402 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2404 } elsif (my $avail = $scfg->{nodes
}) {
2405 foreach my $node (keys %$nodehash) {
2406 if (!$avail->{$node}) {
2407 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2414 foreach my $node (values %$nodehash) {
2415 if (my $unavail = $node->{unavailable_storages
}) {
2416 $node->{unavailable_storages
} = [ sort keys %$unavail ];
2423 # Compat only, use assert_config_exists_on_node and vm_running_locally where possible
2425 my ($vmid, $nocheck, $node) = @_;
2427 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid, $node) if !$nocheck;
2428 return PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
2433 my $vzlist = config_list
();
2435 my $fd = IO
::Dir-
>new($PVE::QemuServer
::Helpers
::var_run_tmpdir
) || return $vzlist;
2437 while (defined(my $de = $fd->read)) {
2438 next if $de !~ m/^(\d+)\.pid$/;
2440 next if !defined($vzlist->{$vmid});
2441 if (my $pid = check_running
($vmid)) {
2442 $vzlist->{$vmid}->{pid
} = $pid;
2449 our $vmstatus_return_properties = {
2450 vmid
=> get_standard_option
('pve-vmid'),
2452 description
=> "Qemu process status.",
2454 enum
=> ['stopped', 'running'],
2457 description
=> "Maximum memory in bytes.",
2460 renderer
=> 'bytes',
2463 description
=> "Root disk size in bytes.",
2466 renderer
=> 'bytes',
2469 description
=> "VM name.",
2474 description
=> "Qemu QMP agent status.",
2479 description
=> "PID of running qemu process.",
2484 description
=> "Uptime.",
2487 renderer
=> 'duration',
2490 description
=> "Maximum usable CPUs.",
2495 description
=> "The current config lock, if any.",
2500 description
=> "The current configured tags, if any",
2506 my $last_proc_pid_stat;
2508 # get VM status information
2509 # This must be fast and should not block ($full == false)
2510 # We only query KVM using QMP if $full == true (this can be slow)
2512 my ($opt_vmid, $full) = @_;
2516 my $storecfg = PVE
::Storage
::config
();
2518 my $list = vzlist
();
2519 my $defaults = load_defaults
();
2521 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2523 my $cpucount = $cpuinfo->{cpus
} || 1;
2525 foreach my $vmid (keys %$list) {
2526 next if $opt_vmid && ($vmid ne $opt_vmid);
2528 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2530 my $d = { vmid
=> $vmid };
2531 $d->{pid
} = $list->{$vmid}->{pid
};
2533 # fixme: better status?
2534 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2536 my $size = PVE
::QemuServer
::Drive
::bootdisk_size
($storecfg, $conf);
2537 if (defined($size)) {
2538 $d->{disk
} = 0; # no info available
2539 $d->{maxdisk
} = $size;
2545 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2546 * ($conf->{cores
} || $defaults->{cores
});
2547 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2548 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2550 $d->{name
} = $conf->{name
} || "VM $vmid";
2551 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2552 : $defaults->{memory
}*(1024*1024);
2554 if ($conf->{balloon
}) {
2555 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2556 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2557 : $defaults->{shares
};
2568 $d->{diskwrite
} = 0;
2570 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2572 $d->{serial
} = 1 if conf_has_serial
($conf);
2573 $d->{lock} = $conf->{lock} if $conf->{lock};
2574 $d->{tags
} = $conf->{tags
} if defined($conf->{tags
});
2579 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2580 foreach my $dev (keys %$netdev) {
2581 next if $dev !~ m/^tap([1-9]\d*)i/;
2583 my $d = $res->{$vmid};
2586 $d->{netout
} += $netdev->{$dev}->{receive
};
2587 $d->{netin
} += $netdev->{$dev}->{transmit
};
2590 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2591 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2596 my $ctime = gettimeofday
;
2598 foreach my $vmid (keys %$list) {
2600 my $d = $res->{$vmid};
2601 my $pid = $d->{pid
};
2604 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2605 next if !$pstat; # not running
2607 my $used = $pstat->{utime} + $pstat->{stime
};
2609 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2611 if ($pstat->{vsize
}) {
2612 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2615 my $old = $last_proc_pid_stat->{$pid};
2617 $last_proc_pid_stat->{$pid} = {
2625 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2627 if ($dtime > 1000) {
2628 my $dutime = $used - $old->{used
};
2630 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2631 $last_proc_pid_stat->{$pid} = {
2637 $d->{cpu
} = $old->{cpu
};
2641 return $res if !$full;
2643 my $qmpclient = PVE
::QMPClient-
>new();
2645 my $ballooncb = sub {
2646 my ($vmid, $resp) = @_;
2648 my $info = $resp->{'return'};
2649 return if !$info->{max_mem
};
2651 my $d = $res->{$vmid};
2653 # use memory assigned to VM
2654 $d->{maxmem
} = $info->{max_mem
};
2655 $d->{balloon
} = $info->{actual
};
2657 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2658 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2659 $d->{freemem
} = $info->{free_mem
};
2662 $d->{ballooninfo
} = $info;
2665 my $blockstatscb = sub {
2666 my ($vmid, $resp) = @_;
2667 my $data = $resp->{'return'} || [];
2668 my $totalrdbytes = 0;
2669 my $totalwrbytes = 0;
2671 for my $blockstat (@$data) {
2672 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2673 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2675 $blockstat->{device
} =~ s/drive-//;
2676 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2678 $res->{$vmid}->{diskread
} = $totalrdbytes;
2679 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2682 my $statuscb = sub {
2683 my ($vmid, $resp) = @_;
2685 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2686 # this fails if ballon driver is not loaded, so this must be
2687 # the last commnand (following command are aborted if this fails).
2688 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2690 my $status = 'unknown';
2691 if (!defined($status = $resp->{'return'}->{status
})) {
2692 warn "unable to get VM status\n";
2696 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2699 foreach my $vmid (keys %$list) {
2700 next if $opt_vmid && ($vmid ne $opt_vmid);
2701 next if !$res->{$vmid}->{pid
}; # not running
2702 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2705 $qmpclient->queue_execute(undef, 2);
2707 foreach my $vmid (keys %$list) {
2708 next if $opt_vmid && ($vmid ne $opt_vmid);
2709 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2715 sub conf_has_serial
{
2718 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2719 if ($conf->{"serial$i"}) {
2727 sub conf_has_audio
{
2728 my ($conf, $id) = @_;
2731 my $audio = $conf->{"audio$id"};
2732 return undef if !defined($audio);
2734 my $audioproperties = PVE
::JSONSchema
::parse_property_string
($audio_fmt, $audio);
2735 my $audiodriver = $audioproperties->{driver
} // 'spice';
2738 dev
=> $audioproperties->{device
},
2739 dev_id
=> "audiodev$id",
2740 backend
=> $audiodriver,
2741 backend_id
=> "$audiodriver-backend${id}",
2745 sub vga_conf_has_spice
{
2748 my $vgaconf = parse_vga
($vga);
2749 my $vgatype = $vgaconf->{type
};
2750 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
2757 return get_host_arch
() eq $arch;
2762 return $conf->{arch
} // get_host_arch
();
2765 my $default_machines = {
2770 sub get_vm_machine
{
2771 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
2773 my $machine = $forcemachine || $conf->{machine
};
2775 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
2777 $machine ||= $default_machines->{$arch};
2778 if ($add_pve_version) {
2779 $kvmversion //= kvm_user_version
();
2780 my $pvever = PVE
::QemuServer
::Machine
::get_pve_version
($kvmversion);
2781 $machine .= "+pve$pvever";
2785 if ($add_pve_version && $machine !~ m/\+pve\d+$/) {
2786 # for version-pinned machines that do not include a pve-version (e.g.
2787 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
2788 $machine .= '+pve0';
2794 sub get_ovmf_files
($) {
2797 my $ovmf = $OVMF->{$arch}
2798 or die "no OVMF images known for architecture '$arch'\n";
2804 aarch64
=> '/usr/bin/qemu-system-aarch64',
2805 x86_64
=> '/usr/bin/qemu-system-x86_64',
2807 sub get_command_for_arch
($) {
2809 return '/usr/bin/kvm' if is_native
($arch);
2811 my $cmd = $Arch2Qemu->{$arch}
2812 or die "don't know how to emulate architecture '$arch'\n";
2816 # To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
2817 # to use in a QEMU command line (-cpu element), first array_intersect the result
2818 # of query_supported_ with query_understood_. This is necessary because:
2820 # a) query_understood_ returns flags the host cannot use and
2821 # b) query_supported_ (rather the QMP call) doesn't actually return CPU
2822 # flags, but CPU settings - with most of them being flags. Those settings
2823 # (and some flags, curiously) cannot be specified as a "-cpu" argument.
2825 # query_supported_ needs to start up to 2 temporary VMs and is therefore rather
2826 # expensive. If you need the value returned from this, you can get it much
2827 # cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
2828 # $accel being 'kvm' or 'tcg'.
2830 # pvestatd calls this function on startup and whenever the QEMU/KVM version
2831 # changes, automatically populating pmxcfs.
2833 # Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
2834 # since kvm and tcg machines support different flags
2836 sub query_supported_cpu_flags
{
2839 $arch //= get_host_arch
();
2840 my $default_machine = $default_machines->{$arch};
2844 # FIXME: Once this is merged, the code below should work for ARM as well:
2845 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
2846 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
2849 my $kvm_supported = defined(kvm_version
());
2850 my $qemu_cmd = get_command_for_arch
($arch);
2852 my $pidfile = PVE
::QemuServer
::Helpers
::pidfile_name
($fakevmid);
2854 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
2855 my $query_supported_run_qemu = sub {
2861 '-machine', $default_machine,
2863 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server,nowait",
2864 '-mon', 'chardev=qmp,mode=control',
2865 '-pidfile', $pidfile,
2870 push @$cmd, '-accel', 'tcg';
2873 my $rc = run_command
($cmd, noerr
=> 1, quiet
=> 0);
2874 die "QEMU flag querying VM exited with code " . $rc if $rc;
2877 my $cmd_result = mon_cmd
(
2879 'query-cpu-model-expansion',
2881 model
=> { name
=> 'host' }
2884 my $props = $cmd_result->{model
}->{props
};
2885 foreach my $prop (keys %$props) {
2886 next if $props->{$prop} ne '1';
2887 # QEMU returns some flags multiple times, with '_', '.' or '-'
2888 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
2889 # We only keep those with underscores, to match /proc/cpuinfo
2890 $prop =~ s/\.|-/_/g;
2891 $flags->{$prop} = 1;
2896 # force stop with 10 sec timeout and 'nocheck'
2897 # always stop, even if QMP failed
2898 vm_stop
(undef, $fakevmid, 1, 1, 10, 0, 1);
2902 return [ sort keys %$flags ];
2905 # We need to query QEMU twice, since KVM and TCG have different supported flags
2906 PVE
::QemuConfig-
>lock_config($fakevmid, sub {
2907 $flags->{tcg
} = eval { $query_supported_run_qemu->(0) };
2908 warn "warning: failed querying supported tcg flags: $@\n" if $@;
2910 if ($kvm_supported) {
2911 $flags->{kvm
} = eval { $query_supported_run_qemu->(1) };
2912 warn "warning: failed querying supported kvm flags: $@\n" if $@;
2919 # Understood CPU flags are written to a file at 'pve-qemu' compile time
2920 my $understood_cpu_flag_dir = "/usr/share/kvm";
2921 sub query_understood_cpu_flags
{
2922 my $arch = get_host_arch
();
2923 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
2925 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
2928 my $raw = file_get_contents
($filepath);
2929 $raw =~ s/^\s+|\s+$//g;
2930 my @flags = split(/\s+/, $raw);
2935 sub config_to_command
{
2936 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
2939 my $globalFlags = [];
2940 my $machineFlags = [];
2945 my $ostype = $conf->{ostype
};
2946 my $winversion = windows_version
($ostype);
2947 my $kvm = $conf->{kvm
};
2948 my $nodename = nodename
();
2950 my $arch = get_vm_arch
($conf);
2951 my $kvm_binary = get_command_for_arch
($arch);
2952 my $kvmver = kvm_user_version
($kvm_binary);
2954 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
2955 $kvmver //= "undefined";
2956 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
2959 my $add_pve_version = min_version
($kvmver, 4, 1);
2961 my $machine_type = get_vm_machine
($conf, $forcemachine, $arch, $add_pve_version);
2962 my $machine_version = PVE
::QemuServer
::Machine
::extract_version
($machine_type, $kvmver);
2963 $kvm //= 1 if is_native
($arch);
2965 $machine_version =~ m/(\d+)\.(\d+)/;
2966 my ($machine_major, $machine_minor) = ($1, $2);
2967 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type', please upgrade node '$nodename'\n"
2968 if !PVE
::QemuServer
::min_version
($kvmver, $machine_major, $machine_minor);
2970 if (!PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($machine_version, $kvmver)) {
2971 my $max_pve_version = PVE
::QemuServer
::Machine
::get_pve_version
($machine_version);
2972 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is pve$max_pve_version)"
2973 . " is too old to run machine type '$machine_type', please upgrade node '$nodename'\n";
2976 # if a specific +pve version is required for a feature, use $version_guard
2977 # instead of min_version to allow machines to be run with the minimum
2979 my $required_pve_version = 0;
2980 my $version_guard = sub {
2981 my ($major, $minor, $pve) = @_;
2982 return 0 if !min_version
($machine_version, $major, $minor, $pve);
2983 my $max_pve = PVE
::QemuServer
::Machine
::get_pve_version
("$major.$minor");
2984 return 1 if min_version
($machine_version, $major, $minor, $max_pve+1);
2985 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
2990 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
2991 if !defined kvm_version
();
2994 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
2995 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
2996 my $use_old_bios_files = undef;
2997 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
2999 my $cpuunits = defined($conf->{cpuunits
}) ?
3000 $conf->{cpuunits
} : $defaults->{cpuunits
};
3002 push @$cmd, $kvm_binary;
3004 push @$cmd, '-id', $vmid;
3006 my $vmname = $conf->{name
} || "vm$vmid";
3008 push @$cmd, '-name', $vmname;
3012 my $qmpsocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid);
3013 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3014 push @$cmd, '-mon', "chardev=qmp,mode=control";
3016 if (min_version
($machine_version, 2, 12)) {
3017 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3018 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3021 push @$cmd, '-pidfile' , PVE
::QemuServer
::Helpers
::pidfile_name
($vmid);
3023 push @$cmd, '-daemonize';
3025 if ($conf->{smbios1
}) {
3026 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3027 if ($smbios_conf->{base64
}) {
3028 # Do not pass base64 flag to qemu
3029 delete $smbios_conf->{base64
};
3030 my $smbios_string = "";
3031 foreach my $key (keys %$smbios_conf) {
3033 if ($key eq "uuid") {
3034 $value = $smbios_conf->{uuid
}
3036 $value = decode_base64
($smbios_conf->{$key});
3038 # qemu accepts any binary data, only commas need escaping by double comma
3040 $smbios_string .= "," . $key . "=" . $value if $value;
3042 push @$cmd, '-smbios', "type=1" . $smbios_string;
3044 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3048 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3049 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3050 die "uefi base image not found\n" if ! -f
$ovmf_code;
3054 if (my $efidisk = $conf->{efidisk0
}) {
3055 my $d = parse_drive
('efidisk0', $efidisk);
3056 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3057 $format = $d->{format
};
3059 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3060 if (!defined($format)) {
3061 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3062 $format = qemu_img_format
($scfg, $volname);
3066 die "efidisk format must be specified\n"
3067 if !defined($format);
3070 warn "no efidisk configured! Using temporary efivars disk.\n";
3071 $path = "/tmp/$vmid-ovmf.fd";
3072 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3078 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3079 $size_str = ",size=" . (-s
$ovmf_vars);
3082 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3083 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0$size_str,file=$path";
3088 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
3089 if (min_version
($machine_version, 4, 0)) {
3090 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3092 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3096 if ($conf->{vmgenid
}) {
3097 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3100 # add usb controllers
3101 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3102 push @$devices, @usbcontrollers if @usbcontrollers;
3103 my $vga = parse_vga
($conf->{vga
});
3105 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3106 $vga->{type
} = 'qxl' if $qxlnum;
3108 if (!$vga->{type
}) {
3109 if ($arch eq 'aarch64') {
3110 $vga->{type
} = 'virtio';
3111 } elsif (min_version
($machine_version, 2, 9)) {
3112 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3114 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3118 # enable absolute mouse coordinates (needed by vnc)
3120 if (defined($conf->{tablet
})) {
3121 $tablet = $conf->{tablet
};
3123 $tablet = $defaults->{tablet
};
3124 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3125 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3129 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3130 my $kbd = print_keyboarddevice_full
($conf, $arch);
3131 push @$devices, '-device', $kbd if defined($kbd);
3135 my $gpu_passthrough;
3138 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3139 my $id = "hostpci$i";
3140 my $d = parse_hostpci
($conf->{$id});
3143 if (my $pcie = $d->{pcie
}) {
3144 die "q35 machine model is not enabled" if !$q35;
3145 # win7 wants to have the pcie devices directly on the pcie bus
3146 # instead of in the root port
3147 if ($winversion == 7) {
3148 $pciaddr = print_pcie_addr
("${id}bus0");
3150 # add more root ports if needed, 4 are present by default
3151 # by pve-q35 cfgs, rest added here on demand.
3153 push @$devices, '-device', print_pcie_root_port
($i);
3155 $pciaddr = print_pcie_addr
($id);
3158 $pciaddr = print_pci_addr
($id, $bridges, $arch, $machine_type);
3162 if ($d->{'x-vga'}) {
3163 $xvga = ',x-vga=on' if !($conf->{bios
} && $conf->{bios
} eq 'ovmf');
3165 $vga->{type
} = 'none' if !defined($conf->{vga
});
3166 $gpu_passthrough = 1;
3169 my $pcidevices = $d->{pciid
};
3170 my $multifunction = 1 if @$pcidevices > 1;
3173 if ($d->{mdev
} && scalar(@$pcidevices) == 1) {
3174 my $pci_id = $pcidevices->[0]->{id
};
3175 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $i);
3176 $sysfspath = "/sys/bus/pci/devices/$pci_id/$uuid";
3177 } elsif ($d->{mdev
}) {
3178 warn "ignoring mediated device '$id' with multifunction device\n";
3182 foreach my $pcidevice (@$pcidevices) {
3183 my $devicestr = "vfio-pci";
3186 $devicestr .= ",sysfsdev=$sysfspath";
3188 $devicestr .= ",host=$pcidevice->{id}";
3191 my $mf_addr = $multifunction ?
".$j" : '';
3192 $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}";
3195 $devicestr .= ',rombar=0' if defined($d->{rombar
}) && !$d->{rombar
};
3196 $devicestr .= "$xvga";
3197 $devicestr .= ",multifunction=on" if $multifunction;
3198 $devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile
};
3201 push @$devices, '-device', $devicestr;
3207 my $usb_dev_features = {};
3208 $usb_dev_features->{spice_usb3
} = 1 if min_version
($machine_version, 4, 0);
3210 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES, $usb_dev_features);
3211 push @$devices, @usbdevices if @usbdevices;
3213 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3214 if (my $path = $conf->{"serial$i"}) {
3215 if ($path eq 'socket') {
3216 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3217 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3218 # On aarch64, serial0 is the UART device. Qemu only allows
3219 # connecting UART devices via the '-serial' command line, as
3220 # the device has a fixed slot on the hardware...
3221 if ($arch eq 'aarch64' && $i == 0) {
3222 push @$devices, '-serial', "chardev:serial$i";
3224 push @$devices, '-device', "isa-serial,chardev=serial$i";
3227 die "no such serial device\n" if ! -c
$path;
3228 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3229 push @$devices, '-device', "isa-serial,chardev=serial$i";
3235 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3236 if (my $path = $conf->{"parallel$i"}) {
3237 die "no such parallel device\n" if ! -c
$path;
3238 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3239 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3240 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3244 if (my $audio = conf_has_audio
($conf)) {
3246 my $audiopciaddr = print_pci_addr
("audio0", $bridges, $arch, $machine_type);
3248 my $id = $audio->{dev_id
};
3249 if ($audio->{dev
} eq 'AC97') {
3250 push @$devices, '-device', "AC97,id=${id}${audiopciaddr}";
3251 } elsif ($audio->{dev
} =~ /intel\-hda$/) {
3252 push @$devices, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
3253 push @$devices, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0";
3254 push @$devices, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1";
3256 die "unkown audio device '$audio->{dev}', implement me!";
3259 push @$devices, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
3263 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3264 $sockets = $conf->{sockets
} if $conf->{sockets
};
3266 my $cores = $conf->{cores
} || 1;
3268 my $maxcpus = $sockets * $cores;
3270 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3272 my $allowed_vcpus = $cpuinfo->{cpus
};
3274 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3275 if ($allowed_vcpus < $maxcpus);
3277 if($hotplug_features->{cpu
} && min_version
($machine_version, 2, 7)) {
3279 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3280 for (my $i = 2; $i <= $vcpus; $i++) {
3281 my $cpustr = print_cpu_device
($conf,$i);
3282 push @$cmd, '-device', $cpustr;
3287 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3289 push @$cmd, '-nodefaults';
3291 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3293 my $bootindex_hash = {};
3295 foreach my $o (split(//, $bootorder)) {
3296 $bootindex_hash->{$o} = $i*100;
3300 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3302 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3304 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3306 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3307 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
3308 my $socket = PVE
::QemuServer
::Helpers
::vnc_socket
($vmid);
3309 push @$cmd, '-vnc', "unix:$socket,password";
3311 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3312 push @$cmd, '-nographic';
3316 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3318 my $useLocaltime = $conf->{localtime};
3320 if ($winversion >= 5) { # windows
3321 $useLocaltime = 1 if !defined($conf->{localtime});
3323 # use time drift fix when acpi is enabled
3324 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3325 $tdf = 1 if !defined($conf->{tdf
});
3329 if ($winversion >= 6) {
3330 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3331 push @$cmd, '-no-hpet';
3334 push @$rtcFlags, 'driftfix=slew' if $tdf;
3336 if (($conf->{startdate
}) && ($conf->{startdate
} ne 'now')) {
3337 push @$rtcFlags, "base=$conf->{startdate}";
3338 } elsif ($useLocaltime) {
3339 push @$rtcFlags, 'base=localtime';
3342 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
3344 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3346 push @$cmd, '-S' if $conf->{freeze
};
3348 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3350 my $guest_agent = parse_guest_agent
($conf);
3352 if ($guest_agent->{enabled
}) {
3353 my $qgasocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid, 1);
3354 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3356 if (!$guest_agent->{type
} || $guest_agent->{type
} eq 'virtio') {
3357 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3358 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3359 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3360 } elsif ($guest_agent->{type
} eq 'isa') {
3361 push @$devices, '-device', "isa-serial,chardev=qga0";
3365 my $rng = parse_rng
($conf->{rng0
}) if $conf->{rng0
};
3366 if ($rng && &$version_guard(4, 1, 2)) {
3367 my $max_bytes = $rng->{max_bytes
} // $rng_fmt->{max_bytes
}->{default};
3368 my $period = $rng->{period
} // $rng_fmt->{period
}->{default};
3370 my $limiter_str = "";
3372 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3375 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
3376 die "cannot create VirtIO RNG device: source file '$rng->{source}' doesn't exist\n"
3377 if ! -e
$rng->{source
};
3379 my $rng_addr = print_pci_addr
("rng0", $bridges, $arch, $machine_type);
3381 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3382 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3390 for(my $i = 1; $i < $qxlnum; $i++){
3391 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
3394 # assume other OS works like Linux
3395 my ($ram, $vram) = ("134217728", "67108864");
3396 if ($vga->{memory
}) {
3397 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3398 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3400 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3401 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3405 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3407 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3408 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3409 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3411 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3412 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3413 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3415 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3416 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3418 my $spice_enhancement = PVE
::JSONSchema
::parse_property_string
($spice_enhancements_fmt, $conf->{spice_enhancements
} // '');
3419 if ($spice_enhancement->{foldersharing
}) {
3420 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3421 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3424 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3425 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}" if $spice_enhancement->{videostreaming
};
3426 push @$devices, '-spice', "$spice_opts";
3429 # enable balloon by default, unless explicitly disabled
3430 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3431 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3432 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3435 if ($conf->{watchdog
}) {
3436 my $wdopts = parse_watchdog
($conf->{watchdog
});
3437 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3438 my $watchdog = $wdopts->{model
} || 'i6300esb';
3439 push @$devices, '-device', "$watchdog$pciaddr";
3440 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3444 my $scsicontroller = {};
3445 my $ahcicontroller = {};
3446 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3448 # Add iscsi initiator name if available
3449 if (my $initiator = get_initiator_name
()) {
3450 push @$devices, '-iscsi', "initiator-name=$initiator";
3453 foreach_drive
($conf, sub {
3454 my ($ds, $drive) = @_;
3456 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3457 push @$vollist, $drive->{file
};
3460 # ignore efidisk here, already added in bios/fw handling code above
3461 return if $drive->{interface
} eq 'efidisk';
3463 $use_virtio = 1 if $ds =~ m/^virtio/;
3465 if (drive_is_cdrom
($drive)) {
3466 if ($bootindex_hash->{d
}) {
3467 $drive->{bootindex
} = $bootindex_hash->{d
};
3468 $bootindex_hash->{d
} += 1;
3471 if ($bootindex_hash->{c
}) {
3472 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3473 $bootindex_hash->{c
} += 1;
3477 if($drive->{interface
} eq 'virtio'){
3478 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3481 if ($drive->{interface
} eq 'scsi') {
3483 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3485 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3486 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3488 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3489 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3492 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3493 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3494 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3495 } elsif ($drive->{iothread
}) {
3496 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3500 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3501 $queues = ",num_queues=$drive->{queues}";
3504 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3505 $scsicontroller->{$controller}=1;
3508 if ($drive->{interface
} eq 'sata') {
3509 my $controller = int($drive->{index} / $PVE::QemuServer
::Drive
::MAX_SATA_DISKS
);
3510 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3511 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3512 $ahcicontroller->{$controller}=1;
3515 my $drive_cmd = print_drive_commandline_full
($storecfg, $vmid, $drive);
3516 push @$devices, '-drive',$drive_cmd;
3517 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3520 for (my $i = 0; $i < $MAX_NETS; $i++) {
3521 next if !$conf->{"net$i"};
3522 my $d = parse_net
($conf->{"net$i"});
3525 $use_virtio = 1 if $d->{model
} eq 'virtio';
3527 if ($bootindex_hash->{n
}) {
3528 $d->{bootindex
} = $bootindex_hash->{n
};
3529 $bootindex_hash->{n
} += 1;
3532 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
3533 push @$devices, '-netdev', $netdevfull;
3535 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
3536 push @$devices, '-device', $netdevicefull;
3539 if ($conf->{ivshmem
}) {
3540 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
3544 $bus = print_pcie_addr
("ivshmem");
3546 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
3549 my $ivshmem_name = $ivshmem->{name
} // $vmid;
3550 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3552 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
3553 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
3556 # pci.4 is nested in pci.1
3557 $bridges->{1} = 1 if $bridges->{4};
3561 if (min_version
($machine_version, 2, 3)) {
3566 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3570 for my $k (sort {$b cmp $a} keys %$bridges) {
3571 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
3572 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
3573 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3575 # add after -readconfig pve-q35.cfg
3576 splice @$devices, 2, 0, '-device', $devstr;
3578 unshift @$devices, '-device', $devstr if $k > 0;
3583 push @$machineFlags, 'accel=tcg';
3586 my $machine_type_min = $machine_type;
3587 if ($add_pve_version) {
3588 $machine_type_min =~ s/\+pve\d+$//;
3589 $machine_type_min .= "+pve$required_pve_version";
3591 push @$machineFlags, "type=${machine_type_min}";
3593 push @$cmd, @$devices;
3594 push @$cmd, '-rtc', join(',', @$rtcFlags)
3595 if scalar(@$rtcFlags);
3596 push @$cmd, '-machine', join(',', @$machineFlags)
3597 if scalar(@$machineFlags);
3598 push @$cmd, '-global', join(',', @$globalFlags)
3599 if scalar(@$globalFlags);
3601 if (my $vmstate = $conf->{vmstate
}) {
3602 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
3603 push @$vollist, $vmstate;
3604 push @$cmd, '-loadstate', $statepath;
3605 print "activating and using '$vmstate' as vmstate\n";
3609 if ($conf->{args
}) {
3610 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3614 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3620 my $res = mon_cmd
($vmid, 'query-spice');
3622 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3625 sub vm_devices_list
{
3628 my $res = mon_cmd
($vmid, 'query-pci');
3629 my $devices_to_check = [];
3631 foreach my $pcibus (@$res) {
3632 push @$devices_to_check, @{$pcibus->{devices
}},
3635 while (@$devices_to_check) {
3637 for my $d (@$devices_to_check) {
3638 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3639 next if !$d->{'pci_bridge'};
3641 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3642 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3644 $devices_to_check = $to_check;
3647 my $resblock = mon_cmd
($vmid, 'query-block');
3648 foreach my $block (@$resblock) {
3649 if($block->{device
} =~ m/^drive-(\S+)/){
3654 my $resmice = mon_cmd
($vmid, 'query-mice');
3655 foreach my $mice (@$resmice) {
3656 if ($mice->{name
} eq 'QEMU HID Tablet') {
3657 $devices->{tablet
} = 1;
3662 # for usb devices there is no query-usb
3663 # but we can iterate over the entries in
3664 # qom-list path=/machine/peripheral
3665 my $resperipheral = mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3666 foreach my $per (@$resperipheral) {
3667 if ($per->{name
} =~ m/^usb\d+$/) {
3668 $devices->{$per->{name
}} = 1;
3676 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
3678 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3680 my $devices_list = vm_devices_list
($vmid);
3681 return 1 if defined($devices_list->{$deviceid});
3683 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
3685 if ($deviceid eq 'tablet') {
3687 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
3689 } elsif ($deviceid eq 'keyboard') {
3691 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
3693 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3695 die "usb hotplug currently not reliable\n";
3696 # since we can't reliably hot unplug all added usb devices
3697 # and usb passthrough disables live migration
3698 # we disable usb hotplugging for now
3699 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3701 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3703 qemu_iothread_add
($vmid, $deviceid, $device);
3705 qemu_driveadd
($storecfg, $vmid, $device);
3706 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
3708 qemu_deviceadd
($vmid, $devicefull);
3709 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3711 eval { qemu_drivedel
($vmid, $deviceid); };
3716 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3719 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3720 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
3721 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3723 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3725 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3726 qemu_iothread_add
($vmid, $deviceid, $device);
3727 $devicefull .= ",iothread=iothread-$deviceid";
3730 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3731 $devicefull .= ",num_queues=$device->{queues}";
3734 qemu_deviceadd
($vmid, $devicefull);
3735 qemu_deviceaddverify
($vmid, $deviceid);
3737 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3739 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
3740 qemu_driveadd
($storecfg, $vmid, $device);
3742 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
3743 eval { qemu_deviceadd
($vmid, $devicefull); };
3745 eval { qemu_drivedel
($vmid, $deviceid); };
3750 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3752 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
3754 my $machine_type = PVE
::QemuServer
::Machine
::qemu_machine_pxe
($vmid, $conf);
3755 my $use_old_bios_files = undef;
3756 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3758 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
3759 qemu_deviceadd
($vmid, $netdevicefull);
3761 qemu_deviceaddverify
($vmid, $deviceid);
3762 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
3765 eval { qemu_netdevdel
($vmid, $deviceid); };
3770 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3773 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
3774 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3776 qemu_deviceadd
($vmid, $devicefull);
3777 qemu_deviceaddverify
($vmid, $deviceid);
3780 die "can't hotplug device '$deviceid'\n";
3786 # fixme: this should raise exceptions on error!
3787 sub vm_deviceunplug
{
3788 my ($vmid, $conf, $deviceid) = @_;
3790 my $devices_list = vm_devices_list
($vmid);
3791 return 1 if !defined($devices_list->{$deviceid});
3793 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3795 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
3797 qemu_devicedel
($vmid, $deviceid);
3799 } elsif ($deviceid =~ m/^usb\d+$/) {
3801 die "usb hotplug currently not reliable\n";
3802 # when unplugging usb devices this way,
3803 # there may be remaining usb controllers/hubs
3804 # so we disable it for now
3805 qemu_devicedel
($vmid, $deviceid);
3806 qemu_devicedelverify
($vmid, $deviceid);
3808 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3810 qemu_devicedel
($vmid, $deviceid);
3811 qemu_devicedelverify
($vmid, $deviceid);
3812 qemu_drivedel
($vmid, $deviceid);
3813 qemu_iothread_del
($conf, $vmid, $deviceid);
3815 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3817 qemu_devicedel
($vmid, $deviceid);
3818 qemu_devicedelverify
($vmid, $deviceid);
3819 qemu_iothread_del
($conf, $vmid, $deviceid);
3821 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3823 qemu_devicedel
($vmid, $deviceid);
3824 qemu_drivedel
($vmid, $deviceid);
3825 qemu_deletescsihw
($conf, $vmid, $deviceid);
3827 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3829 qemu_devicedel
($vmid, $deviceid);
3830 qemu_devicedelverify
($vmid, $deviceid);
3831 qemu_netdevdel
($vmid, $deviceid);
3834 die "can't unplug device '$deviceid'\n";
3840 sub qemu_deviceadd
{
3841 my ($vmid, $devicefull) = @_;
3843 $devicefull = "driver=".$devicefull;
3844 my %options = split(/[=,]/, $devicefull);
3846 mon_cmd
($vmid, "device_add" , %options);
3849 sub qemu_devicedel
{
3850 my ($vmid, $deviceid) = @_;
3852 my $ret = mon_cmd
($vmid, "device_del", id
=> $deviceid);
3855 sub qemu_iothread_add
{
3856 my($vmid, $deviceid, $device) = @_;
3858 if ($device->{iothread
}) {
3859 my $iothreads = vm_iothreads_list
($vmid);
3860 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3864 sub qemu_iothread_del
{
3865 my($conf, $vmid, $deviceid) = @_;
3867 my $confid = $deviceid;
3868 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
3869 $confid = 'scsi' . $1;
3871 my $device = parse_drive
($confid, $conf->{$confid});
3872 if ($device->{iothread
}) {
3873 my $iothreads = vm_iothreads_list
($vmid);
3874 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3878 sub qemu_objectadd
{
3879 my($vmid, $objectid, $qomtype) = @_;
3881 mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3886 sub qemu_objectdel
{
3887 my($vmid, $objectid) = @_;
3889 mon_cmd
($vmid, "object-del", id
=> $objectid);
3895 my ($storecfg, $vmid, $device) = @_;
3897 my $drive = print_drive_commandline_full
($storecfg, $vmid, $device);
3898 $drive =~ s/\\/\\\\/g;
3899 my $ret = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "drive_add auto \"$drive\"");
3901 # If the command succeeds qemu prints: "OK
"
3902 return 1 if $ret =~ m/OK/s;
3904 die "adding drive failed
: $ret\n";
3908 my($vmid, $deviceid) = @_;
3910 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-
$deviceid");
3913 return 1 if $ret eq "";
3915 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3916 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3918 die "deleting drive
$deviceid failed
: $ret\n";
3921 sub qemu_deviceaddverify {
3922 my ($vmid, $deviceid) = @_;
3924 for (my $i = 0; $i <= 5; $i++) {
3925 my $devices_list = vm_devices_list($vmid);
3926 return 1 if defined($devices_list->{$deviceid});
3930 die "error on hotplug device
'$deviceid'\n";
3934 sub qemu_devicedelverify {
3935 my ($vmid, $deviceid) = @_;
3937 # need to verify that the device is correctly removed as device_del
3938 # is async and empty return is not reliable
3940 for (my $i = 0; $i <= 5; $i++) {
3941 my $devices_list = vm_devices_list($vmid);
3942 return 1 if !defined($devices_list->{$deviceid});
3946 die "error on hot-unplugging device
'$deviceid'\n";
3949 sub qemu_findorcreatescsihw {
3950 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
3952 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3954 my $scsihwid="$controller_prefix$controller";
3955 my $devices_list = vm_devices_list($vmid);
3957 if(!defined($devices_list->{$scsihwid})) {
3958 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
3964 sub qemu_deletescsihw {
3965 my ($conf, $vmid, $opt) = @_;
3967 my $device = parse_drive($opt, $conf->{$opt});
3969 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3970 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3974 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3976 my $devices_list = vm_devices_list($vmid);
3977 foreach my $opt (keys %{$devices_list}) {
3978 if (is_valid_drivename($opt)) {
3979 my $drive = parse_drive($opt, $conf->{$opt});
3980 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3986 my $scsihwid="scsihw
$controller";
3988 vm_deviceunplug($vmid, $conf, $scsihwid);
3993 sub qemu_add_pci_bridge {
3994 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4000 print_pci_addr($device, $bridges, $arch, $machine_type);
4002 while (my ($k, $v) = each %$bridges) {
4005 return 1 if !defined($bridgeid) || $bridgeid < 1;
4007 my $bridge = "pci
.$bridgeid";
4008 my $devices_list = vm_devices_list($vmid);
4010 if (!defined($devices_list->{$bridge})) {
4011 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4017 sub qemu_set_link_status {
4018 my ($vmid, $device, $up) = @_;
4020 mon_cmd($vmid, "set_link
", name => $device,
4021 up => $up ? JSON::true : JSON::false);
4024 sub qemu_netdevadd {
4025 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4027 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4028 my %options = split(/[=,]/, $netdev);
4030 mon_cmd($vmid, "netdev_add
", %options);
4034 sub qemu_netdevdel {
4035 my ($vmid, $deviceid) = @_;
4037 mon_cmd($vmid, "netdev_del
", id => $deviceid);
4040 sub qemu_usb_hotplug {
4041 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4045 # remove the old one first
4046 vm_deviceunplug($vmid, $conf, $deviceid);
4048 # check if xhci controller is necessary and available
4049 if ($device->{usb3}) {
4051 my $devicelist = vm_devices_list($vmid);
4053 if (!$devicelist->{xhci}) {
4054 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4055 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4058 my $d = parse_usb_device($device->{host});
4059 $d->{usb3} = $device->{usb3};
4062 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4065 sub qemu_cpu_hotplug {
4066 my ($vmid, $conf, $vcpus) = @_;
4068 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
4071 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4072 $sockets = $conf->{sockets} if $conf->{sockets};
4073 my $cores = $conf->{cores} || 1;
4074 my $maxcpus = $sockets * $cores;
4076 $vcpus = $maxcpus if !$vcpus;
4078 die "you can
't add more vcpus than maxcpus\n"
4079 if $vcpus > $maxcpus;
4081 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4083 if ($vcpus < $currentvcpus) {
4085 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4087 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4088 qemu_devicedel($vmid, "cpu$i");
4090 my $currentrunningvcpus = undef;
4092 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4093 last if scalar(@{$currentrunningvcpus}) == $i-1;
4094 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4098 #update conf after each succesfull cpu unplug
4099 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4100 PVE::QemuConfig->write_config($vmid, $conf);
4103 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4109 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4110 die "vcpus in running vm does not match its configuration\n"
4111 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4113 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4115 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4116 my $cpustr = print_cpu_device($conf, $i);
4117 qemu_deviceadd($vmid, $cpustr);
4120 my $currentrunningvcpus = undef;
4122 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4123 last if scalar(@{$currentrunningvcpus}) == $i;
4124 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4128 #update conf after each succesfull cpu hotplug
4129 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4130 PVE::QemuConfig->write_config($vmid, $conf);
4134 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4135 mon_cmd($vmid, "cpu-add", id => int($i));
4140 sub qemu_block_set_io_throttle {
4141 my ($vmid, $deviceid,
4142 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4143 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4144 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4145 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4147 return if !check_running($vmid) ;
4149 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4151 bps_rd => int($bps_rd),
4152 bps_wr => int($bps_wr),
4154 iops_rd => int($iops_rd),
4155 iops_wr => int($iops_wr),
4156 bps_max => int($bps_max),
4157 bps_rd_max => int($bps_rd_max),
4158 bps_wr_max => int($bps_wr_max),
4159 iops_max => int($iops_max),
4160 iops_rd_max => int($iops_rd_max),
4161 iops_wr_max => int($iops_wr_max),
4162 bps_max_length => int($bps_max_length),
4163 bps_rd_max_length => int($bps_rd_max_length),
4164 bps_wr_max_length => int($bps_wr_max_length),
4165 iops_max_length => int($iops_max_length),
4166 iops_rd_max_length => int($iops_rd_max_length),
4167 iops_wr_max_length => int($iops_wr_max_length),
4172 # old code, only used to shutdown old VM after update
4174 my ($fh, $timeout) = @_;
4176 my $sel = new IO::Select;
4183 while (scalar (@ready = $sel->can_read($timeout))) {
4185 if ($count = $fh->sysread($buf, 8192)) {
4186 if ($buf =~ /^(.*)\(qemu\) $/s) {
4193 if (!defined($count)) {
4200 die "monitor read timeout\n" if !scalar(@ready);
4205 sub qemu_block_resize {
4206 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4208 my $running = check_running($vmid);
4210 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4212 return if !$running;
4214 my $padding = (1024 - $size % 1024) % 1024;
4215 $size = $size + $padding;
4217 mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4221 sub qemu_volume_snapshot {
4222 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4224 my $running = check_running($vmid);
4226 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4227 mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4229 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4233 sub qemu_volume_snapshot_delete {
4234 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4236 my $running = check_running($vmid);
4241 my $conf = PVE::QemuConfig->load_config($vmid);
4242 foreach_drive($conf, sub {
4243 my ($ds, $drive) = @_;
4244 $running = 1 if $drive->{file} eq $volid;
4248 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4249 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4251 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4255 sub set_migration_caps {
4261 "auto-converge" => 1,
4263 "x-rdma-pin-all" => 0,
4268 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
4270 for my $supported_capability (@$supported_capabilities) {
4272 capability => $supported_capability->{capability},
4273 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4277 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4280 my $fast_plug_option = {
4288 'vmstatestorage
' => 1,
4293 # hotplug changes in [PENDING]
4294 # $selection hash can be used to only apply specified options, for
4295 # example: { cores => 1 } (only apply changed 'cores
')
4296 # $errors ref is used to return error messages
4297 sub vmconfig_hotplug_pending {
4298 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4300 my $defaults = load_defaults();
4301 my $arch = get_vm_arch($conf);
4302 my $machine_type = get_vm_machine($conf, undef, $arch);
4304 # commit values which do not have any impact on running VM first
4305 # Note: those option cannot raise errors, we we do not care about
4306 # $selection and always apply them.
4308 my $add_error = sub {
4309 my ($opt, $msg) = @_;
4310 $errors->{$opt} = "hotplug problem - $msg";
4314 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4315 if ($fast_plug_option->{$opt}) {
4316 $conf->{$opt} = $conf->{pending}->{$opt};
4317 delete $conf->{pending}->{$opt};
4323 PVE::QemuConfig->write_config($vmid, $conf);
4326 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4328 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4329 foreach my $opt (sort keys %$pending_delete_hash) {
4330 next if $selection && !$selection->{$opt};
4331 my $force = $pending_delete_hash->{$opt}->{force};
4333 if ($opt eq 'hotplug
') {
4334 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4335 } elsif ($opt eq 'tablet
') {
4336 die "skip\n" if !$hotplug_features->{usb};
4337 if ($defaults->{tablet}) {
4338 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4339 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4340 if $arch eq 'aarch64
';
4342 vm_deviceunplug($vmid, $conf, 'tablet
');
4343 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4345 } elsif ($opt =~ m/^usb\d+/) {
4347 # since we cannot reliably hot unplug usb devices
4348 # we are disabling it
4349 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4350 vm_deviceunplug($vmid, $conf, $opt);
4351 } elsif ($opt eq 'vcpus
') {
4352 die "skip\n" if !$hotplug_features->{cpu};
4353 qemu_cpu_hotplug($vmid, $conf, undef);
4354 } elsif ($opt eq 'balloon
') {
4355 # enable balloon device is not hotpluggable
4356 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4357 # here we reset the ballooning value to memory
4358 my $balloon = $conf->{memory} || $defaults->{memory};
4359 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4360 } elsif ($fast_plug_option->{$opt}) {
4362 } elsif ($opt =~ m/^net(\d+)$/) {
4363 die "skip\n" if !$hotplug_features->{network};
4364 vm_deviceunplug($vmid, $conf, $opt);
4365 } elsif (is_valid_drivename($opt)) {
4366 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4367 vm_deviceunplug($vmid, $conf, $opt);
4368 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4369 } elsif ($opt =~ m/^memory$/) {
4370 die "skip\n" if !$hotplug_features->{memory};
4371 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4372 } elsif ($opt eq 'cpuunits
') {
4373 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4374 } elsif ($opt eq 'cpulimit
') {
4375 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4381 &$add_error($opt, $err) if $err ne "skip\n";
4383 delete $conf->{$opt};
4384 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4388 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
4389 $apply_pending_cloudinit = sub {
4390 return if $apply_pending_cloudinit_done; # once is enough
4391 $apply_pending_cloudinit_done = 1; # once is enough
4393 my ($key, $value) = @_;
4395 my @cloudinit_opts = keys %$confdesc_cloudinit;
4396 foreach my $opt (keys %{$conf->{pending}}) {
4397 next if !grep { $_ eq $opt } @cloudinit_opts;
4398 $conf->{$opt} = delete $conf->{pending}->{$opt};
4401 my $new_conf = { %$conf };
4402 $new_conf->{$key} = $value;
4403 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4406 foreach my $opt (keys %{$conf->{pending}}) {
4407 next if $selection && !$selection->{$opt};
4408 my $value = $conf->{pending}->{$opt};
4410 if ($opt eq 'hotplug
') {
4411 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4412 } elsif ($opt eq 'tablet
') {
4413 die "skip\n" if !$hotplug_features->{usb};
4415 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4416 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4417 if $arch eq 'aarch64
';
4418 } elsif ($value == 0) {
4419 vm_deviceunplug($vmid, $conf, 'tablet
');
4420 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4422 } elsif ($opt =~ m/^usb\d+$/) {
4424 # since we cannot reliably hot unplug usb devices
4425 # we are disabling it
4426 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4427 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4428 die "skip\n" if !$d;
4429 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4430 } elsif ($opt eq 'vcpus
') {
4431 die "skip\n" if !$hotplug_features->{cpu};
4432 qemu_cpu_hotplug($vmid, $conf, $value);
4433 } elsif ($opt eq 'balloon
') {
4434 # enable/disable balloning device is not hotpluggable
4435 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4436 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4437 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4439 # allow manual ballooning if shares is set to zero
4440 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4441 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4442 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4444 } elsif ($opt =~ m/^net(\d+)$/) {
4445 # some changes can be done without hotplug
4446 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4447 $vmid, $opt, $value, $arch, $machine_type);
4448 } elsif (is_valid_drivename($opt)) {
4449 die "skip\n" if $opt eq 'efidisk0
';
4450 # some changes can be done without hotplug
4451 my $drive = parse_drive($opt, $value);
4452 if (drive_is_cloudinit($drive)) {
4453 &$apply_pending_cloudinit($opt, $value);
4455 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4456 $vmid, $opt, $value, $arch, $machine_type);
4457 } elsif ($opt =~ m/^memory$/) { #dimms
4458 die "skip\n" if !$hotplug_features->{memory};
4459 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4460 } elsif ($opt eq 'cpuunits
') {
4461 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4462 } elsif ($opt eq 'cpulimit
') {
4463 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4464 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4466 die "skip\n"; # skip non-hot-pluggable options
4470 &$add_error($opt, $err) if $err ne "skip\n";
4472 $conf->{$opt} = $value;
4473 delete $conf->{pending}->{$opt};
4477 PVE::QemuConfig->write_config($vmid, $conf);
4480 sub try_deallocate_drive {
4481 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4483 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4484 my $volid = $drive->{file};
4485 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4486 my $sid = PVE::Storage::parse_volume_id($volid);
4487 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4489 # check if the disk is really unused
4490 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4491 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
4492 PVE::Storage::vdisk_free($storecfg, $volid);
4495 # If vm is not owner of this disk remove from config
4503 sub vmconfig_delete_or_detach_drive {
4504 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4506 my $drive = parse_drive($opt, $conf->{$opt});
4508 my $rpcenv = PVE::RPCEnvironment::get();
4509 my $authuser = $rpcenv->get_user();
4512 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4513 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4515 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4521 sub vmconfig_apply_pending {
4522 my ($vmid, $conf, $storecfg, $errors) = @_;
4524 my $add_apply_error = sub {
4525 my ($opt, $msg) = @_;
4526 my $err_msg = "unable to apply pending change $opt : $msg";
4527 $errors->{$opt} = $err_msg;
4533 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4534 foreach my $opt (sort keys %$pending_delete_hash) {
4535 my $force = $pending_delete_hash->{$opt}->{force};
4537 if ($opt =~ m/^unused/) {
4538 die "internal error";
4539 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4540 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4544 $add_apply_error->($opt, $err);
4546 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4547 delete $conf->{$opt};
4551 PVE::QemuConfig->cleanup_pending($conf);
4553 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4554 next if $opt eq 'delete'; # just to be sure
4556 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4557 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4561 $add_apply_error->($opt, $err);
4563 $conf->{$opt} = delete $conf->{pending}->{$opt};
4567 # write all changes at once to avoid unnecessary i/o
4568 PVE::QemuConfig->write_config($vmid, $conf);
4571 sub vmconfig_update_net {
4572 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4574 my $newnet = parse_net($value);
4576 if ($conf->{$opt}) {
4577 my $oldnet = parse_net($conf->{$opt});
4579 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4580 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4581 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4582 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4584 # for non online change, we try to hot-unplug
4585 die "skip\n" if !$hotplug;
4586 vm_deviceunplug($vmid, $conf, $opt);
4589 die "internal error" if $opt !~ m/net(\d+)/;
4590 my $iface = "tap${vmid}i$1";
4592 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4593 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4594 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4595 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4596 PVE::Network::tap_unplug($iface);
4599 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4601 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4603 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4604 # Rate can be applied on its own but any change above needs to
4605 # include the rate in tap_plug since OVS resets everything.
4606 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4609 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4610 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4618 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4624 sub vmconfig_update_disk {
4625 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4627 my $drive = parse_drive($opt, $value);
4629 if ($conf->{$opt}) {
4631 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4633 my $media = $drive->{media} || 'disk
';
4634 my $oldmedia = $old_drive->{media} || 'disk
';
4635 die "unable to change media type\n" if $media ne $oldmedia;
4637 if (!drive_is_cdrom($old_drive)) {
4639 if ($drive->{file} ne $old_drive->{file}) {
4641 die "skip\n" if !$hotplug;
4643 # unplug and register as unused
4644 vm_deviceunplug($vmid, $conf, $opt);
4645 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4648 # update existing disk
4650 # skip non hotpluggable value
4651 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4652 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4653 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4654 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
4655 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
4660 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4661 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4662 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4663 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4664 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4665 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4666 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4667 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4668 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4669 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4670 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4671 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4672 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4673 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4674 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4675 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4676 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4677 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4679 qemu_block_set_io_throttle($vmid,"drive-$opt",
4680 ($drive->{mbps} || 0)*1024*1024,
4681 ($drive->{mbps_rd} || 0)*1024*1024,
4682 ($drive->{mbps_wr} || 0)*1024*1024,
4683 $drive->{iops} || 0,
4684 $drive->{iops_rd} || 0,
4685 $drive->{iops_wr} || 0,
4686 ($drive->{mbps_max} || 0)*1024*1024,
4687 ($drive->{mbps_rd_max} || 0)*1024*1024,
4688 ($drive->{mbps_wr_max} || 0)*1024*1024,
4689 $drive->{iops_max} || 0,
4690 $drive->{iops_rd_max} || 0,
4691 $drive->{iops_wr_max} || 0,
4692 $drive->{bps_max_length} || 1,
4693 $drive->{bps_rd_max_length} || 1,
4694 $drive->{bps_wr_max_length} || 1,
4695 $drive->{iops_max_length} || 1,
4696 $drive->{iops_rd_max_length} || 1,
4697 $drive->{iops_wr_max_length} || 1);
4706 if ($drive->{file} eq 'none
') {
4707 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
4708 if (drive_is_cloudinit($old_drive)) {
4709 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4712 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4714 # force eject if locked
4715 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
4718 mon_cmd($vmid, "blockdev-change-medium",
4719 id => "$opt", filename => "$path");
4728 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4730 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4731 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
4734 # called in locked context by incoming migration
4735 sub vm_migrate_get_nbd_disks {
4736 my ($storecfg, $conf, $replicated_volumes) = @_;
4738 my $local_volumes = {};
4739 foreach_drive($conf, sub {
4740 my ($ds, $drive) = @_;
4742 return if drive_is_cdrom($drive);
4744 my $volid = $drive->{file};
4748 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4750 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4751 return if $scfg->{shared};
4753 # replicated disks re-use existing state via bitmap
4754 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
4755 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
4757 return $local_volumes;
4760 # called in locked context by incoming migration
4761 sub vm_migrate_alloc_nbd_disks {
4762 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
4767 foreach my $opt (sort keys %$source_volumes) {
4768 my ($volid, $storeid, $volname, $drive, $use_existing) = @{$source_volumes->{$opt}};
4770 if ($use_existing) {
4771 $nbd->{$opt}->{drivestr} = print_drive($drive);
4772 $nbd->{$opt}->{volid} = $volid;
4773 $nbd->{$opt}->{replicated} = 1;
4777 # If a remote storage is specified and the format of the original
4778 # volume is not available there, fall back to the default format.
4779 # Otherwise use the same format as the original.
4780 if (!$storagemap->{identity}) {
4781 $storeid = map_storage($storagemap, $storeid);
4782 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4783 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4784 my $fileFormat = qemu_img_format($scfg, $volname);
4785 $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
4787 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4788 $format = qemu_img_format($scfg, $volname);
4791 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4792 my $newdrive = $drive;
4793 $newdrive->{format} = $format;
4794 $newdrive->{file} = $newvolid;
4795 my $drivestr = print_drive($newdrive);
4796 $nbd->{$opt}->{drivestr} = $drivestr;
4797 $nbd->{$opt}->{volid} = $newvolid;
4803 # see vm_start_nolock for parameters, additionally:
4805 # storagemap = parsed storage map for allocating NBD disks
4807 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
4809 return PVE::QemuConfig->lock_config($vmid, sub {
4810 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
4812 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4814 $params->{resume} = PVE::QemuConfig->has_lock($conf, 'suspended
');
4816 PVE::QemuConfig->check_lock($conf)
4817 if !($params->{skiplock} || $params->{resume});
4819 die "VM $vmid already running\n" if check_running($vmid, undef, $migrate_opts->{migratedfrom});
4821 if (my $storagemap = $migrate_opts->{storagemap}) {
4822 my $replicated = $migrate_opts->{replicated_volumes};
4823 my $disks = vm_migrate_get_nbd_disks($storecfg, $conf, $replicated);
4824 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $disks, $storagemap);
4826 foreach my $opt (keys %{$migrate_opts->{nbd}}) {
4827 $conf->{$opt} = $migrate_opts->{nbd}->{$opt}->{drivestr};
4831 return vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
4837 # statefile => 'tcp
', 'unix
' for migration or path/volid for RAM state
4838 # skiplock => 0/1, skip checking for config lock
4839 # forcemachine => to force Qemu machine (rollback/migration)
4840 # timeout => in seconds
4841 # paused => start VM in paused state (backup)
4842 # resume => resume from hibernation
4844 # nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
4845 # migratedfrom => source node
4846 # spice_ticket => used for spice migration, passed via tunnel/stdin
4847 # network => CIDR of migration network
4848 # type => secure/insecure - tunnel over encrypted connection or plain-text
4849 # nbd_proto_version => int, 0 for TCP, 1 for UNIX
4850 # replicated_volumes = which volids should be re-used with bitmaps for nbd migration
4851 sub vm_start_nolock {
4852 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
4854 my $statefile = $params->{statefile};
4855 my $resume = $params->{resume};
4857 my $migratedfrom = $migrate_opts->{migratedfrom};
4858 my $migration_type = $migrate_opts->{type};
4862 # clean up leftover reboot request files
4863 eval { clear_reboot_request($vmid); };
4866 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4867 vmconfig_apply_pending($vmid, $conf, $storecfg);
4868 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4871 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4873 my $defaults = load_defaults();
4875 # set environment variable useful inside network script
4876 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4878 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start
', 1);
4880 my $forcemachine = $params->{forcemachine};
4882 # enforce machine type on suspended vm to ensure HW compatibility
4883 $forcemachine = $conf->{runningmachine};
4884 print "Resuming suspended VM\n";
4887 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4890 my $get_migration_ip = sub {
4891 my ($nodename) = @_;
4893 return $migration_ip if defined($migration_ip);
4895 my $cidr = $migrate_opts->{network};
4897 if (!defined($cidr)) {
4898 my $dc_conf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4899 $cidr = $dc_conf->{migration}->{network};
4902 if (defined($cidr)) {
4903 my $ips = PVE::Network::get_local_ip_from_cidr($cidr);
4905 die "could not get IP: no address configured on local " .
4906 "node for network '$cidr'\n" if scalar(@$ips) == 0;
4908 die "could not get IP: multiple addresses configured on local " .
4909 "node for network '$cidr'\n" if scalar(@$ips) > 1;
4911 $migration_ip = @$ips[0];
4914 $migration_ip = PVE::Cluster::remote_node_ip($nodename, 1)
4915 if !defined($migration_ip);
4917 return $migration_ip;
4922 if ($statefile eq 'tcp
') {
4923 my $localip = "localhost";
4924 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4925 my $nodename = nodename();
4927 if (!defined($migration_type)) {
4928 if (defined($datacenterconf->{migration}->{type})) {
4929 $migration_type = $datacenterconf->{migration}->{type};
4931 $migration_type = 'secure
';
4935 if ($migration_type eq 'insecure
') {
4936 $localip = $get_migration_ip->($nodename);
4937 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4940 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4941 my $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4942 $migrate_uri = "tcp:${localip}:${migrate_port}";
4943 push @$cmd, '-incoming
', $migrate_uri;
4946 } elsif ($statefile eq 'unix
') {
4947 # should be default for secure migrations as a ssh TCP forward
4948 # tunnel is not deterministic reliable ready and fails regurarly
4949 # to set up in time, so use UNIX socket forwards
4950 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4951 unlink $socket_addr;
4953 $migrate_uri = "unix:$socket_addr";
4955 push @$cmd, '-incoming
', $migrate_uri;
4958 } elsif (-e $statefile) {
4959 push @$cmd, '-loadstate
', $statefile;
4961 my $statepath = PVE::Storage::path($storecfg, $statefile);
4962 push @$vollist, $statefile;
4963 push @$cmd, '-loadstate
', $statepath;
4965 } elsif ($params->{paused}) {
4970 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4971 my $d = parse_hostpci($conf->{"hostpci$i"});
4973 my $pcidevices = $d->{pciid};
4974 foreach my $pcidevice (@$pcidevices) {
4975 my $pciid = $pcidevice->{id};
4977 my $info = PVE::SysFSTools::pci_device_info("$pciid");
4978 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
4979 die "no pci device info for device '$pciid'\n" if !$info;
4982 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
4983 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
4985 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
4986 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
4987 die "can
't reset pci device '$pciid'\n"
4988 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
4993 PVE::Storage::activate_volumes($storecfg, $vollist);
4996 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4997 outfunc => sub {}, errfunc => sub {});
4999 # Issues with the above 'stop
' not being fully completed are extremely rare, a very low
5000 # timeout should be more than enough here...
5001 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
5003 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5004 : $defaults->{cpuunits};
5006 my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $resume);
5008 timeout => $statefile ? undef : $start_timeout,
5013 # when migrating, prefix QEMU output so other side can pick up any
5014 # errors that might occur and show the user
5015 if ($migratedfrom) {
5016 $run_params{quiet} = 1;
5017 $run_params{logfunc} = sub { print "QEMU: $_[0]\n" };
5021 Slice => 'qemu
.slice
',
5023 CPUShares => $cpuunits
5026 if (my $cpulimit = $conf->{cpulimit}) {
5027 $properties{CPUQuota} = int($cpulimit * 100);
5029 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5031 my $run_qemu = sub {
5032 PVE::Tools::run_fork sub {
5033 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5035 my $exitcode = run_command($cmd, %run_params);
5036 die "QEMU exited with code $exitcode\n" if $exitcode;
5040 if ($conf->{hugepages}) {
5043 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5044 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5046 PVE::QemuServer::Memory::hugepages_mount();
5047 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5049 eval { $run_qemu->() };
5051 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5055 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5057 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5060 eval { $run_qemu->() };
5064 # deactivate volumes if start fails
5065 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5066 die "start failed: $err";
5069 print "migration listens on $migrate_uri\n" if $migrate_uri;
5070 $res->{migrate_uri} = $migrate_uri;
5072 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5073 eval { mon_cmd($vmid, "cont"); };
5077 #start nbd server for storage migration
5078 if (my $nbd = $migrate_opts->{nbd}) {
5079 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version} // 0;
5081 my $migrate_storage_uri;
5082 # nbd_protocol_version > 0 for unix socket support
5083 if ($nbd_protocol_version > 0 && $migration_type eq 'secure
') {
5084 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5085 mon_cmd($vmid, "nbd-server-start", addr => { type => 'unix
', data => { path => $socket_path } } );
5086 $migrate_storage_uri = "nbd:unix:$socket_path";
5088 my $nodename = nodename();
5089 my $localip = $get_migration_ip->($nodename);
5090 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5091 my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
5093 mon_cmd($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${storage_migrate_port}" } } );
5094 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5095 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
5098 $res->{migrate_storage_uri} = $migrate_storage_uri;
5100 foreach my $opt (sort keys %$nbd) {
5101 my $drivestr = $nbd->{$opt}->{drivestr};
5102 my $volid = $nbd->{$opt}->{volid};
5103 mon_cmd($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5104 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
5105 print "storage migration listens on $nbd_uri volume:$drivestr\n";
5106 print "re-using replicated volume: $opt - $volid\n"
5107 if $nbd->{$opt}->{replicated};
5109 $res->{drives}->{$opt} = $nbd->{$opt};
5110 $res->{drives}->{$opt}->{nbd_uri} = $nbd_uri;
5114 if ($migratedfrom) {
5116 set_migration_caps($vmid);
5121 print "spice listens on port $spice_port\n";
5122 $res->{spice_port} = $spice_port;
5123 if ($migrate_opts->{spice_ticket}) {
5124 mon_cmd($vmid, "set_password", protocol => 'spice
', password => $migrate_opts->{spice_ticket});
5125 mon_cmd($vmid, "expire_password", protocol => 'spice
', time => "+30");
5130 mon_cmd($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5131 if !$statefile && $conf->{balloon};
5133 foreach my $opt (keys %$conf) {
5134 next if $opt !~ m/^net\d+$/;
5135 my $nicconf = parse_net($conf->{$opt});
5136 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5140 mon_cmd($vmid, 'qom-set
',
5141 path => "machine/peripheral/balloon0",
5142 property => "guest-stats-polling-interval",
5143 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5146 print "Resumed VM, removing state\n";
5147 if (my $vmstate = $conf->{vmstate}) {
5148 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5149 PVE::Storage::vdisk_free($storecfg, $vmstate);
5151 delete $conf->@{qw(lock vmstate runningmachine)};
5152 PVE
::QemuConfig-
>write_config($vmid, $conf);
5155 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
5160 sub vm_commandline
{
5161 my ($storecfg, $vmid, $snapname) = @_;
5163 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5167 my $snapshot = $conf->{snapshots
}->{$snapname};
5168 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5170 # check for a 'runningmachine' in snapshot
5171 $forcemachine = $snapshot->{runningmachine
} if $snapshot->{runningmachine
};
5173 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
5178 my $defaults = load_defaults
();
5180 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults, $forcemachine);
5182 return PVE
::Tools
::cmd2string
($cmd);
5186 my ($vmid, $skiplock) = @_;
5188 PVE
::QemuConfig-
>lock_config($vmid, sub {
5190 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5192 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5194 mon_cmd
($vmid, "system_reset");
5198 sub get_vm_volumes
{
5202 foreach_volid
($conf, sub {
5203 my ($volid, $attr) = @_;
5205 return if $volid =~ m
|^/|;
5207 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5210 push @$vollist, $volid;
5216 sub vm_stop_cleanup
{
5217 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5222 my $vollist = get_vm_volumes
($conf);
5223 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5226 foreach my $ext (qw(mon qmp pid vnc qga)) {
5227 unlink "/var/run/qemu-server/${vmid}.$ext";
5230 if ($conf->{ivshmem
}) {
5231 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5232 # just delete it for now, VMs which have this already open do not
5233 # are affected, but new VMs will get a separated one. If this
5234 # becomes an issue we either add some sort of ref-counting or just
5235 # add a "don't delete on stop" flag to the ivshmem format.
5236 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5239 foreach my $key (keys %$conf) {
5240 next if $key !~ m/^hostpci(\d+)$/;
5241 my $hostpciindex = $1;
5242 my $d = parse_hostpci
($conf->{$key});
5243 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5245 foreach my $pci (@{$d->{pciid
}}) {
5246 my $pciid = $pci->{id
};
5247 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5251 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5253 warn $@ if $@; # avoid errors - just warn
5256 # call only in locked context
5258 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
5260 my $pid = check_running
($vmid, $nocheck);
5265 $conf = PVE
::QemuConfig-
>load_config($vmid);
5266 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5267 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5268 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5269 $timeout = $opts->{down
} if $opts->{down
};
5271 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5276 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5277 mon_cmd
($vmid, "guest-shutdown", timeout
=> $timeout);
5279 mon_cmd
($vmid, "system_powerdown");
5282 mon_cmd
($vmid, "quit");
5288 $timeout = 60 if !defined($timeout);
5291 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5296 if ($count >= $timeout) {
5298 warn "VM still running - terminating now with SIGTERM\n";
5301 die "VM quit/powerdown failed - got timeout\n";
5304 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5309 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5312 die "VM quit/powerdown failed\n";
5320 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5325 if ($count >= $timeout) {
5326 warn "VM still running - terminating now with SIGKILL\n";
5331 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5334 # Note: use $nocheck to skip tests if VM configuration file exists.
5335 # We need that when migration VMs to other nodes (files already moved)
5336 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5338 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5340 $force = 1 if !defined($force) && !$shutdown;
5343 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5344 kill 15, $pid if $pid;
5345 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5346 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5350 PVE
::QemuConfig-
>lock_config($vmid, sub {
5351 _do_vm_stop
($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
5356 my ($vmid, $timeout) = @_;
5358 PVE
::QemuConfig-
>lock_config($vmid, sub {
5361 # only reboot if running, as qmeventd starts it again on a stop event
5362 return if !check_running
($vmid);
5364 create_reboot_request
($vmid);
5366 my $storecfg = PVE
::Storage
::config
();
5367 _do_vm_stop
($storecfg, $vmid, undef, undef, $timeout, 1);
5371 # avoid that the next normal shutdown will be confused for a reboot
5372 clear_reboot_request
($vmid);
5378 # note: if using the statestorage parameter, the caller has to check privileges
5380 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
5387 PVE
::QemuConfig-
>lock_config($vmid, sub {
5389 $conf = PVE
::QemuConfig-
>load_config($vmid);
5391 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5392 PVE
::QemuConfig-
>check_lock($conf)
5393 if !($skiplock || $is_backing_up);
5395 die "cannot suspend to disk during backup\n"
5396 if $is_backing_up && $includestate;
5398 if ($includestate) {
5399 $conf->{lock} = 'suspending';
5400 my $date = strftime
("%Y-%m-%d", localtime(time()));
5401 $storecfg = PVE
::Storage
::config
();
5402 if (!$statestorage) {
5403 $statestorage = find_vmstate_storage
($conf, $storecfg);
5404 # check permissions for the storage
5405 my $rpcenv = PVE
::RPCEnvironment
::get
();
5406 if ($rpcenv->{type
} ne 'cli') {
5407 my $authuser = $rpcenv->get_user();
5408 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
5413 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
5414 $path = PVE
::Storage
::path
($storecfg, $vmstate);
5415 PVE
::QemuConfig-
>write_config($vmid, $conf);
5417 mon_cmd
($vmid, "stop");
5421 if ($includestate) {
5423 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
5426 mon_cmd
($vmid, "savevm-start", statefile
=> $path);
5428 my $state = mon_cmd
($vmid, "query-savevm");
5429 if (!$state->{status
}) {
5430 die "savevm not active\n";
5431 } elsif ($state->{status
} eq 'active') {
5434 } elsif ($state->{status
} eq 'completed') {
5435 print "State saved, quitting\n";
5437 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
5438 die "query-savevm failed with error '$state->{error}'\n"
5440 die "query-savevm returned status '$state->{status}'\n";
5446 PVE
::QemuConfig-
>lock_config($vmid, sub {
5447 $conf = PVE
::QemuConfig-
>load_config($vmid);
5449 # cleanup, but leave suspending lock, to indicate something went wrong
5451 mon_cmd
($vmid, "savevm-end");
5452 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5453 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5454 delete $conf->@{qw(vmstate runningmachine)};
5455 PVE
::QemuConfig-
>write_config($vmid, $conf);
5461 die "lock changed unexpectedly\n"
5462 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
5464 mon_cmd
($vmid, "quit");
5465 $conf->{lock} = 'suspended';
5466 PVE
::QemuConfig-
>write_config($vmid, $conf);
5472 my ($vmid, $skiplock, $nocheck) = @_;
5474 PVE
::QemuConfig-
>lock_config($vmid, sub {
5475 my $res = mon_cmd
($vmid, 'query-status');
5476 my $resume_cmd = 'cont';
5478 if ($res->{status
} && $res->{status
} eq 'suspended') {
5479 $resume_cmd = 'system_wakeup';
5484 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5486 PVE
::QemuConfig-
>check_lock($conf)
5487 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5490 mon_cmd
($vmid, $resume_cmd);
5495 my ($vmid, $skiplock, $key) = @_;
5497 PVE
::QemuConfig-
>lock_config($vmid, sub {
5499 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5501 # there is no qmp command, so we use the human monitor command
5502 my $res = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "sendkey $key");
5503 die $res if $res ne '';
5507 # vzdump restore implementaion
5509 sub tar_archive_read_firstfile
{
5510 my $archive = shift;
5512 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5514 # try to detect archive type first
5515 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5516 die "unable to open file '$archive'\n";
5517 my $firstfile = <$fh>;
5521 die "ERROR: archive contaions no data\n" if !$firstfile;
5527 sub tar_restore_cleanup
{
5528 my ($storecfg, $statfile) = @_;
5530 print STDERR
"starting cleanup\n";
5532 if (my $fd = IO
::File-
>new($statfile, "r")) {
5533 while (defined(my $line = <$fd>)) {
5534 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5537 if ($volid =~ m
|^/|) {
5538 unlink $volid || die 'unlink failed\n';
5540 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5542 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5544 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5546 print STDERR
"unable to parse line in statfile - $line";
5553 sub restore_file_archive
{
5554 my ($archive, $vmid, $user, $opts) = @_;
5556 my $format = $opts->{format
};
5559 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5560 $format = 'tar' if !$format;
5562 } elsif ($archive =~ m/\.tar$/) {
5563 $format = 'tar' if !$format;
5564 } elsif ($archive =~ m/.tar.lzo$/) {
5565 $format = 'tar' if !$format;
5567 } elsif ($archive =~ m/\.vma$/) {
5568 $format = 'vma' if !$format;
5569 } elsif ($archive =~ m/\.vma\.gz$/) {
5570 $format = 'vma' if !$format;
5572 } elsif ($archive =~ m/\.vma\.lzo$/) {
5573 $format = 'vma' if !$format;
5576 $format = 'vma' if !$format; # default
5579 # try to detect archive format
5580 if ($format eq 'tar') {
5581 return restore_tar_archive
($archive, $vmid, $user, $opts);
5583 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5587 # hepler to remove disks that will not be used after restore
5588 my $restore_cleanup_oldconf = sub {
5589 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
5591 foreach_drive
($oldconf, sub {
5592 my ($ds, $drive) = @_;
5594 return if drive_is_cdrom
($drive, 1);
5596 my $volid = $drive->{file
};
5597 return if !$volid || $volid =~ m
|^/|;
5599 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
5600 return if !$path || !$owner || ($owner != $vmid);
5602 # Note: only delete disk we want to restore
5603 # other volumes will become unused
5604 if ($virtdev_hash->{$ds}) {
5605 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid); };
5612 # delete vmstate files, after the restore we have no snapshots anymore
5613 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5614 my $snap = $oldconf->{snapshots
}->{$snapname};
5615 if ($snap->{vmstate
}) {
5616 eval { PVE
::Storage
::vdisk_free
($storecfg, $snap->{vmstate
}); };
5624 # Helper to parse vzdump backup device hints
5626 # $rpcenv: Environment, used to ckeck storage permissions
5627 # $user: User ID, to check storage permissions
5628 # $storecfg: Storage configuration
5629 # $fh: the file handle for reading the configuration
5630 # $devinfo: should contain device sizes for all backu-up'ed devices
5631 # $options: backup options (pool, default storage)
5633 # Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
5634 my $parse_backup_hints = sub {
5635 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
5637 my $virtdev_hash = {};
5639 while (defined(my $line = <$fh>)) {
5640 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5641 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5642 die "archive does not contain data for drive '$virtdev'\n"
5643 if !$devinfo->{$devname};
5645 if (defined($options->{storage
})) {
5646 $storeid = $options->{storage
} || 'local';
5647 } elsif (!$storeid) {
5650 $format = 'raw' if !$format;
5651 $devinfo->{$devname}->{devname
} = $devname;
5652 $devinfo->{$devname}->{virtdev
} = $virtdev;
5653 $devinfo->{$devname}->{format
} = $format;
5654 $devinfo->{$devname}->{storeid
} = $storeid;
5656 # check permission on storage
5657 my $pool = $options->{pool
}; # todo: do we need that?
5658 if ($user ne 'root@pam') {
5659 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5662 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5663 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
5665 my $drive = parse_drive
($virtdev, $2);
5666 if (drive_is_cloudinit
($drive)) {
5667 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
5668 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5669 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
5671 $virtdev_hash->{$virtdev} = {
5673 storeid
=> $options->{storage
} // $storeid,
5674 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
5681 return $virtdev_hash;
5684 # Helper to allocate and activate all volumes required for a restore
5686 # $storecfg: Storage configuration
5687 # $virtdev_hash: as returned by parse_backup_hints()
5689 # Returns: { $virtdev => $volid }
5690 my $restore_allocate_devices = sub {
5691 my ($storecfg, $virtdev_hash, $vmid) = @_;
5694 foreach my $virtdev (sort keys %$virtdev_hash) {
5695 my $d = $virtdev_hash->{$virtdev};
5696 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5697 my $storeid = $d->{storeid
};
5698 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5700 # test if requested format is supported
5701 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
5702 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5703 $d->{format
} = $defFormat if !$supported;
5706 if ($d->{is_cloudinit
}) {
5707 $name = "vm-$vmid-cloudinit";
5708 $name .= ".$d->{format}" if $d->{format
} ne 'raw';
5711 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
5713 print STDERR
"new volume ID is '$volid'\n";
5714 $d->{volid
} = $volid;
5716 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
5718 $map->{$virtdev} = $volid;
5724 my $restore_update_config_line = sub {
5725 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5727 return if $line =~ m/^\#qmdump\#/;
5728 return if $line =~ m/^\#vzdump\#/;
5729 return if $line =~ m/^lock:/;
5730 return if $line =~ m/^unused\d+:/;
5731 return if $line =~ m/^parent:/;
5733 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5734 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5735 # try to convert old 1.X settings
5736 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5737 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5738 my ($model, $macaddr) = split(/\=/, $devconfig);
5739 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5742 bridge
=> "vmbr$ind",
5743 macaddr
=> $macaddr,
5745 my $netstr = print_net
($net);
5747 print $outfd "net$cookie->{netcount}: $netstr\n";
5748 $cookie->{netcount
}++;
5750 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5751 my ($id, $netstr) = ($1, $2);
5752 my $net = parse_net
($netstr);
5753 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5754 $netstr = print_net
($net);
5755 print $outfd "$id: $netstr\n";
5756 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5759 my $di = parse_drive
($virtdev, $value);
5760 if (defined($di->{backup
}) && !$di->{backup
}) {
5761 print $outfd "#$line";
5762 } elsif ($map->{$virtdev}) {
5763 delete $di->{format
}; # format can change on restore
5764 $di->{file
} = $map->{$virtdev};
5765 $value = print_drive
($di);
5766 print $outfd "$virtdev: $value\n";
5770 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5772 if ($vmgenid ne '0') {
5773 # always generate a new vmgenid if there was a valid one setup
5774 $vmgenid = generate_uuid
();
5776 print $outfd "vmgenid: $vmgenid\n";
5777 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5778 my ($uuid, $uuid_str);
5779 UUID
::generate
($uuid);
5780 UUID
::unparse
($uuid, $uuid_str);
5781 my $smbios1 = parse_smbios1
($2);
5782 $smbios1->{uuid
} = $uuid_str;
5783 print $outfd $1.print_smbios1
($smbios1)."\n";
5789 my $restore_deactivate_volumes = sub {
5790 my ($storecfg, $devinfo) = @_;
5793 foreach my $devname (keys %$devinfo) {
5794 my $volid = $devinfo->{$devname}->{volid
};
5795 push @$vollist, $volid if $volid;
5798 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5801 my $restore_destroy_volumes = sub {
5802 my ($storecfg, $devinfo) = @_;
5804 foreach my $devname (keys %$devinfo) {
5805 my $volid = $devinfo->{$devname}->{volid
};
5808 if ($volid =~ m
|^/|) {
5809 unlink $volid || die 'unlink failed\n';
5811 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5813 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5815 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5820 my ($cfg, $vmid) = @_;
5822 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5824 my $volid_hash = {};
5825 foreach my $storeid (keys %$info) {
5826 foreach my $item (@{$info->{$storeid}}) {
5827 next if !($item->{volid
} && $item->{size
});
5828 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5829 $volid_hash->{$item->{volid
}} = $item;
5836 sub update_disk_config
{
5837 my ($vmid, $conf, $volid_hash) = @_;
5840 my $prefix = "VM $vmid:";
5842 # used and unused disks
5843 my $referenced = {};
5845 # Note: it is allowed to define multiple storages with same path (alias), so
5846 # we need to check both 'volid' and real 'path' (two different volid can point
5847 # to the same path).
5849 my $referencedpath = {};
5852 PVE
::QemuConfig-
>foreach_volume($conf, sub {
5853 my ($opt, $drive) = @_;
5855 my $volid = $drive->{file
};
5858 # mark volid as "in-use" for next step
5859 $referenced->{$volid} = 1;
5860 if ($volid_hash->{$volid} &&
5861 (my $path = $volid_hash->{$volid}->{path
})) {
5862 $referencedpath->{$path} = 1;
5865 return if drive_is_cdrom
($drive);
5866 return if !$volid_hash->{$volid};
5868 my ($updated, $old_size, $new_size) = PVE
::QemuServer
::Drive
::update_disksize
($drive, $volid_hash);
5869 if (defined($updated)) {
5871 $conf->{$opt} = print_drive
($updated);
5872 print "$prefix size of disk '$volid' ($opt) updated from $old_size to $new_size\n";
5876 # remove 'unusedX' entry if volume is used
5877 PVE
::QemuConfig-
>foreach_unused_volume($conf, sub {
5878 my ($opt, $drive) = @_;
5880 my $volid = $drive->{file
};
5883 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5884 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5885 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
5887 delete $conf->{$opt};
5890 $referenced->{$volid} = 1;
5891 $referencedpath->{$path} = 1 if $path;
5894 foreach my $volid (sort keys %$volid_hash) {
5895 next if $volid =~ m/vm-$vmid-state-/;
5896 next if $referenced->{$volid};
5897 my $path = $volid_hash->{$volid}->{path
};
5898 next if !$path; # just to be sure
5899 next if $referencedpath->{$path};
5901 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5902 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
5903 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5910 my ($vmid, $nolock, $dryrun) = @_;
5912 my $cfg = PVE
::Storage
::config
();
5914 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5915 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5916 foreach my $stor (keys %{$cfg->{ids
}}) {
5917 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5920 print "rescan volumes...\n";
5921 my $volid_hash = scan_volids
($cfg, $vmid);
5923 my $updatefn = sub {
5926 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5928 PVE
::QemuConfig-
>check_lock($conf);
5931 foreach my $volid (keys %$volid_hash) {
5932 my $info = $volid_hash->{$volid};
5933 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5936 my $changes = update_disk_config
($vmid, $conf, $vm_volids);
5938 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5941 if (defined($vmid)) {
5945 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5948 my $vmlist = config_list
();
5949 foreach my $vmid (keys %$vmlist) {
5953 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5959 sub restore_proxmox_backup_archive
{
5960 my ($archive, $vmid, $user, $options) = @_;
5962 my $storecfg = PVE
::Storage
::config
();
5964 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($archive);
5965 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5967 my $server = $scfg->{server
};
5968 my $datastore = $scfg->{datastore
};
5969 my $username = $scfg->{username
} // 'root@pam';
5970 my $fingerprint = $scfg->{fingerprint
};
5972 my $repo = "$username\@$server:$datastore";
5973 my $password = PVE
::Storage
::PBSPlugin
::pbs_get_password
($scfg, $storeid);
5974 local $ENV{PBS_PASSWORD
} = $password;
5975 local $ENV{PBS_FINGERPRINT
} = $fingerprint if defined($fingerprint);
5977 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
5978 PVE
::Storage
::parse_volname
($storecfg, $archive);
5980 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
5982 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
5984 my $tmpdir = "/var/tmp/vzdumptmp$$";
5988 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5989 my $tmpfn = "$conffile.$$.tmp";
5990 # disable interrupts (always do cleanups)
5994 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
5996 # Note: $oldconf is undef if VM does not exists
5997 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5998 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6000 my $rpcenv = PVE
::RPCEnvironment
::get
();
6009 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6011 my $cfgfn = "$tmpdir/qemu-server.conf";
6012 my $firewall_config_fn = "$tmpdir/fw.conf";
6013 my $index_fn = "$tmpdir/index.json";
6015 my $cmd = "restore";
6017 my $param = [$pbs_backup_name, "index.json", $index_fn];
6018 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6019 my $index = PVE
::Tools
::file_get_contents
($index_fn);
6020 $index = decode_json
($index);
6022 # print Dumper($index);
6023 foreach my $info (@{$index->{files
}}) {
6024 if ($info->{filename
} =~ m/^(drive-\S+).img.fidx$/) {
6026 if ($info->{size
} =~ m/^(\d+)$/) { # untaint size
6027 $devinfo->{$devname}->{size
} = $1;
6029 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6034 my $is_qemu_server_backup = scalar(grep { $_->{filename
} eq 'qemu-server.conf.blob' } @{$index->{files
}});
6035 if (!$is_qemu_server_backup) {
6036 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6038 my $has_firewall_config = scalar(grep { $_->{filename
} eq 'fw.conf.blob' } @{$index->{files
}});
6040 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6041 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6043 if ($has_firewall_config) {
6044 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6045 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6047 my $pve_firewall_dir = '/etc/pve/firewall';
6048 mkdir $pve_firewall_dir; # make sure the dir exists
6049 PVE
::Tools
::file_copy
($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6052 my $fh = IO
::File-
>new($cfgfn, "r") ||
6053 "unable to read qemu-server.conf - $!\n";
6055 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
6057 # fixme: rate limit?
6059 # create empty/temp config
6060 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\nlock: create");
6062 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6065 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6067 foreach my $virtdev (sort keys %$virtdev_hash) {
6068 my $d = $virtdev_hash->{$virtdev};
6069 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6071 my $volid = $d->{volid
};
6073 my $path = PVE
::Storage
::path
($storecfg, $volid);
6075 my $pbs_restore_cmd = [
6076 '/usr/bin/pbs-restore',
6077 '--repository', $repo,
6079 "$d->{devname}.img.fidx",
6084 if (PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $volid)) {
6085 push @$pbs_restore_cmd, '--skip-zero';
6088 my $dbg_cmdstring = PVE
::Tools
::cmd2string
($pbs_restore_cmd);
6089 print "restore proxmox backup image: $dbg_cmdstring\n";
6090 run_command
($pbs_restore_cmd);
6093 $fh->seek(0, 0) || die "seek failed - $!\n";
6095 my $outfd = new IO
::File
($tmpfn, "w") ||
6096 die "unable to write config for VM $vmid\n";
6098 my $cookie = { netcount
=> 0 };
6099 while (defined(my $line = <$fh>)) {
6100 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $options->{unique
});
6108 $restore_deactivate_volumes->($storecfg, $devinfo);
6114 $restore_destroy_volumes->($storecfg, $devinfo);
6118 rename($tmpfn, $conffile) ||
6119 die "unable to commit configuration file '$conffile'\n";
6121 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6123 eval { rescan
($vmid, 1); };
6127 sub restore_vma_archive
{
6128 my ($archive, $vmid, $user, $opts, $comp) = @_;
6130 my $readfrom = $archive;
6132 my $cfg = PVE
::Storage
::config
();
6134 my $bwlimit = $opts->{bwlimit
};
6136 my $dbg_cmdstring = '';
6137 my $add_pipe = sub {
6139 push @$commands, $cmd;
6140 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6141 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6146 if ($archive eq '-') {
6149 # If we use a backup from a PVE defined storage we also consider that
6150 # storage's rate limit:
6151 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6152 if (defined($volid)) {
6153 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6154 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6156 print STDERR
"applying read rate limit: $readlimit\n";
6157 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6158 $add_pipe->($cstream);
6165 if ($comp eq 'gzip') {
6166 $cmd = ['zcat', $readfrom];
6167 } elsif ($comp eq 'lzop') {
6168 $cmd = ['lzop', '-d', '-c', $readfrom];
6170 die "unknown compression method '$comp'\n";
6175 my $tmpdir = "/var/tmp/vzdumptmp$$";
6178 # disable interrupts (always do cleanups)
6182 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6184 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6185 POSIX
::mkfifo
($mapfifo, 0600);
6188 my $openfifo = sub {
6189 open($fifofh, '>', $mapfifo) || die $!;
6192 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6199 my $rpcenv = PVE
::RPCEnvironment
::get
();
6201 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6202 my $tmpfn = "$conffile.$$.tmp";
6204 # Note: $oldconf is undef if VM does not exist
6205 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6206 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6210 my $print_devmap = sub {
6211 my $cfgfn = "$tmpdir/qemu-server.conf";
6213 # we can read the config - that is already extracted
6214 my $fh = IO
::File-
>new($cfgfn, "r") ||
6215 "unable to read qemu-server.conf - $!\n";
6217 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6219 my $pve_firewall_dir = '/etc/pve/firewall';
6220 mkdir $pve_firewall_dir; # make sure the dir exists
6221 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6224 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
6226 foreach my $key (keys %storage_limits) {
6227 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6229 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6230 $storage_limits{$key} = $limit * 1024;
6233 foreach my $devname (keys %$devinfo) {
6234 die "found no device mapping information for device '$devname'\n"
6235 if !$devinfo->{$devname}->{virtdev
};
6238 # create empty/temp config
6240 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6241 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
6245 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
6247 # print restore information to $fifofh
6248 foreach my $virtdev (sort keys %$virtdev_hash) {
6249 my $d = $virtdev_hash->{$virtdev};
6250 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6252 my $storeid = $d->{storeid
};
6253 my $volid = $d->{volid
};
6256 if (my $limit = $storage_limits{$storeid}) {
6257 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6260 my $write_zeros = 1;
6261 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6265 my $path = PVE
::Storage
::path
($cfg, $volid);
6267 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6269 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6272 $fh->seek(0, 0) || die "seek failed - $!\n";
6274 my $outfd = new IO
::File
($tmpfn, "w") ||
6275 die "unable to write config for VM $vmid\n";
6277 my $cookie = { netcount
=> 0 };
6278 while (defined(my $line = <$fh>)) {
6279 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6292 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6293 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6295 $oldtimeout = alarm($timeout);
6302 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6303 my ($dev_id, $size, $devname) = ($1, $2, $3);
6304 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6305 } elsif ($line =~ m/^CTIME: /) {
6306 # we correctly received the vma config, so we can disable
6307 # the timeout now for disk allocation (set to 10 minutes, so
6308 # that we always timeout if something goes wrong)
6311 print $fifofh "done\n";
6312 my $tmp = $oldtimeout || 0;
6313 $oldtimeout = undef;
6319 print "restore vma archive: $dbg_cmdstring\n";
6320 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6324 alarm($oldtimeout) if $oldtimeout;
6326 $restore_deactivate_volumes->($cfg, $devinfo);
6333 $restore_destroy_volumes->($cfg, $devinfo);
6337 rename($tmpfn, $conffile) ||
6338 die "unable to commit configuration file '$conffile'\n";
6340 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6342 eval { rescan
($vmid, 1); };
6346 sub restore_tar_archive
{
6347 my ($archive, $vmid, $user, $opts) = @_;
6349 if ($archive ne '-') {
6350 my $firstfile = tar_archive_read_firstfile
($archive);
6351 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6352 if $firstfile ne 'qemu-server.conf';
6355 my $storecfg = PVE
::Storage
::config
();
6357 # avoid zombie disks when restoring over an existing VM -> cleanup first
6358 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6359 # skiplock=1 because qmrestore has set the 'create' lock itself already
6360 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6361 destroy_vm
($storecfg, $vmid, 1, { lock => 'restore' }) if -f
$vmcfgfn;
6363 my $tocmd = "/usr/lib/qemu-server/qmextract";
6365 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6366 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6367 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6368 $tocmd .= ' --info' if $opts->{info
};
6370 # tar option "xf" does not autodetect compression when read from STDIN,
6371 # so we pipe to zcat
6372 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6373 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6375 my $tmpdir = "/var/tmp/vzdumptmp$$";
6378 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6379 local $ENV{VZDUMP_VMID
} = $vmid;
6380 local $ENV{VZDUMP_USER
} = $user;
6382 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6383 my $tmpfn = "$conffile.$$.tmp";
6385 # disable interrupts (always do cleanups)
6389 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6397 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6399 if ($archive eq '-') {
6400 print "extracting archive from STDIN\n";
6401 run_command
($cmd, input
=> "<&STDIN");
6403 print "extracting archive '$archive'\n";
6407 return if $opts->{info
};
6411 my $statfile = "$tmpdir/qmrestore.stat";
6412 if (my $fd = IO
::File-
>new($statfile, "r")) {
6413 while (defined (my $line = <$fd>)) {
6414 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6415 $map->{$1} = $2 if $1;
6417 print STDERR
"unable to parse line in statfile - $line\n";
6423 my $confsrc = "$tmpdir/qemu-server.conf";
6425 my $srcfd = new IO
::File
($confsrc, "r") ||
6426 die "unable to open file '$confsrc'\n";
6428 my $outfd = new IO
::File
($tmpfn, "w") ||
6429 die "unable to write config for VM $vmid\n";
6431 my $cookie = { netcount
=> 0 };
6432 while (defined (my $line = <$srcfd>)) {
6433 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6441 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6447 rename $tmpfn, $conffile ||
6448 die "unable to commit configuration file '$conffile'\n";
6450 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6452 eval { rescan
($vmid, 1); };
6456 sub foreach_storage_used_by_vm
{
6457 my ($conf, $func) = @_;
6461 foreach_drive
($conf, sub {
6462 my ($ds, $drive) = @_;
6463 return if drive_is_cdrom
($drive);
6465 my $volid = $drive->{file
};
6467 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6468 $sidhash->{$sid} = $sid if $sid;
6471 foreach my $sid (sort keys %$sidhash) {
6476 my $qemu_snap_storage = {
6479 sub do_snapshots_with_qemu
{
6480 my ($storecfg, $volid) = @_;
6482 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6483 my $scfg = $storecfg->{ids
}->{$storage_name};
6485 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
6489 if ($volid =~ m/\.(qcow2|qed)$/){
6496 sub qga_check_running
{
6497 my ($vmid, $nowarn) = @_;
6499 eval { mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6501 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6507 sub template_create
{
6508 my ($vmid, $conf, $disk) = @_;
6510 my $storecfg = PVE
::Storage
::config
();
6512 foreach_drive
($conf, sub {
6513 my ($ds, $drive) = @_;
6515 return if drive_is_cdrom
($drive);
6516 return if $disk && $ds ne $disk;
6518 my $volid = $drive->{file
};
6519 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6521 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6522 $drive->{file
} = $voliddst;
6523 $conf->{$ds} = print_drive
($drive);
6524 PVE
::QemuConfig-
>write_config($vmid, $conf);
6528 sub convert_iscsi_path
{
6531 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
6536 my $initiator_name = get_initiator_name
();
6538 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6539 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6542 die "cannot convert iscsi path '$path', unkown format\n";
6545 sub qemu_img_convert
{
6546 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6548 my $storecfg = PVE
::Storage
::config
();
6549 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6550 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6552 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6556 my $src_is_iscsi = 0;
6560 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6561 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6562 $src_format = qemu_img_format
($src_scfg, $src_volname);
6563 $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6564 $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
6565 $cachemode = 'none' if $src_scfg->{type
} eq 'zfspool';
6566 } elsif (-f
$src_volid) {
6567 $src_path = $src_volid;
6568 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
6573 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
6575 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6576 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6577 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6578 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
6581 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6582 push @$cmd, '-l', "snapshot.name=$snapname"
6583 if $snapname && $src_format && $src_format eq "qcow2";
6584 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6585 push @$cmd, '-T', $cachemode if defined($cachemode);
6587 if ($src_is_iscsi) {
6588 push @$cmd, '--image-opts';
6589 $src_path = convert_iscsi_path
($src_path);
6590 } elsif ($src_format) {
6591 push @$cmd, '-f', $src_format;
6594 if ($dst_is_iscsi) {
6595 push @$cmd, '--target-image-opts';
6596 $dst_path = convert_iscsi_path
($dst_path);
6598 push @$cmd, '-O', $dst_format;
6601 push @$cmd, $src_path;
6603 if (!$dst_is_iscsi && $is_zero_initialized) {
6604 push @$cmd, "zeroinit:$dst_path";
6606 push @$cmd, $dst_path;
6611 if($line =~ m/\((\S+)\/100\
%\)/){
6613 my $transferred = int($size * $percent / 100);
6614 my $remaining = $size - $transferred;
6616 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6621 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6623 die "copy failed: $err" if $err;
6626 sub qemu_img_format
{
6627 my ($scfg, $volname) = @_;
6629 if ($scfg->{path
} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
6636 sub qemu_drive_mirror
{
6637 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
6639 $jobs = {} if !$jobs;
6643 $jobs->{"drive-$drive"} = {};
6645 if ($dst_volid =~ /^nbd:/) {
6646 $qemu_target = $dst_volid;
6649 my $storecfg = PVE
::Storage
::config
();
6650 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6652 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6654 $format = qemu_img_format
($dst_scfg, $dst_volname);
6656 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6658 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6661 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6662 $opts->{format
} = $format if $format;
6664 if (defined($src_bitmap)) {
6665 $opts->{sync
} = 'incremental';
6666 $opts->{bitmap
} = $src_bitmap;
6667 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
6670 if (defined($bwlimit)) {
6671 $opts->{speed
} = $bwlimit * 1024;
6672 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
6674 print "drive mirror is starting for drive-$drive\n";
6677 # if a job already runs for this device we get an error, catch it for cleanup
6678 eval { mon_cmd
($vmid, "drive-mirror", %$opts); };
6680 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6682 die "mirroring error: $err\n";
6685 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $completion, $qga);
6688 # $completion can be either
6689 # 'complete': wait until all jobs are ready, block-job-complete them (default)
6690 # 'cancel': wait until all jobs are ready, block-job-cancel them
6691 # 'skip': wait until all jobs are ready, return with block jobs in ready state
6692 sub qemu_drive_mirror_monitor
{
6693 my ($vmid, $vmiddst, $jobs, $completion, $qga) = @_;
6695 $completion //= 'complete';
6698 my $err_complete = 0;
6701 die "storage migration timed out\n" if $err_complete > 300;
6703 my $stats = mon_cmd
($vmid, "query-block-jobs");
6705 my $running_mirror_jobs = {};
6706 foreach my $stat (@$stats) {
6707 next if $stat->{type
} ne 'mirror';
6708 $running_mirror_jobs->{$stat->{device
}} = $stat;
6711 my $readycounter = 0;
6713 foreach my $job (keys %$jobs) {
6715 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6716 print "$job : finished\n";
6717 delete $jobs->{$job};
6721 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6723 my $busy = $running_mirror_jobs->{$job}->{busy
};
6724 my $ready = $running_mirror_jobs->{$job}->{ready
};
6725 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6726 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6727 my $remaining = $total - $transferred;
6728 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6730 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6733 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6736 last if scalar(keys %$jobs) == 0;
6738 if ($readycounter == scalar(keys %$jobs)) {
6739 print "all mirroring jobs are ready \n";
6740 last if $completion eq 'skip'; #do the complete later
6742 if ($vmiddst && $vmiddst != $vmid) {
6743 my $agent_running = $qga && qga_check_running
($vmid);
6744 if ($agent_running) {
6745 print "freeze filesystem\n";
6746 eval { mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6748 print "suspend vm\n";
6749 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6752 # if we clone a disk for a new target vm, we don't switch the disk
6753 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6755 if ($agent_running) {
6756 print "unfreeze filesystem\n";
6757 eval { mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6759 print "resume vm\n";
6760 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6766 foreach my $job (keys %$jobs) {
6767 # try to switch the disk if source and destination are on the same guest
6768 print "$job: Completing block job...\n";
6771 if ($completion eq 'complete') {
6772 $op = 'block-job-complete';
6773 } elsif ($completion eq 'cancel') {
6774 $op = 'block-job-cancel';
6776 die "invalid completion value: $completion\n";
6778 eval { mon_cmd
($vmid, $op, device
=> $job) };
6779 if ($@ =~ m/cannot be completed/) {
6780 print "$job: Block job cannot be completed, try again.\n";
6783 print "$job: Completed successfully.\n";
6784 $jobs->{$job}->{complete
} = 1;
6795 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6796 die "mirroring error: $err";
6801 sub qemu_blockjobs_cancel
{
6802 my ($vmid, $jobs) = @_;
6804 foreach my $job (keys %$jobs) {
6805 print "$job: Cancelling block job\n";
6806 eval { mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6807 $jobs->{$job}->{cancel
} = 1;
6811 my $stats = mon_cmd
($vmid, "query-block-jobs");
6813 my $running_jobs = {};
6814 foreach my $stat (@$stats) {
6815 $running_jobs->{$stat->{device
}} = $stat;
6818 foreach my $job (keys %$jobs) {
6820 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6821 print "$job: Done.\n";
6822 delete $jobs->{$job};
6826 last if scalar(keys %$jobs) == 0;
6833 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6834 $newvmid, $storage, $format, $full, $newvollist, $jobs, $completion, $qga, $bwlimit, $conf) = @_;
6839 print "create linked clone of drive $drivename ($drive->{file})\n";
6840 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6841 push @$newvollist, $newvolid;
6844 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6845 $storeid = $storage if $storage;
6847 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6848 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6850 print "create full clone of drive $drivename ($drive->{file})\n";
6852 if (drive_is_cloudinit
($drive)) {
6853 $name = "vm-$newvmid-cloudinit";
6854 $name .= ".$dst_format" if $dst_format ne 'raw';
6856 $size = PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
;
6857 } elsif ($drivename eq 'efidisk0') {
6858 $size = get_efivars_size
($conf);
6860 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6861 push @$newvollist, $newvolid;
6863 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6865 if (drive_is_cloudinit
($drive)) {
6869 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6870 if (!$running || $snapname) {
6871 # TODO: handle bwlimits
6872 if ($drivename eq 'efidisk0') {
6873 # the relevant data on the efidisk may be smaller than the source
6874 # e.g. on RBD/ZFS, so we use dd to copy only the amount
6875 # that is given by the OVMF_VARS.fd
6876 my $src_path = PVE
::Storage
::path
($storecfg, $drive->{file
});
6877 my $dst_path = PVE
::Storage
::path
($storecfg, $newvolid);
6878 run_command
(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=1", "count=$size", "if=$src_path", "of=$dst_path"]);
6880 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6884 my $kvmver = get_running_qemu_version
($vmid);
6885 if (!min_version
($kvmver, 2, 7)) {
6886 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6887 if $drive->{iothread
};
6890 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $completion, $qga, $bwlimit);
6895 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6898 $disk->{format
} = undef;
6899 $disk->{file
} = $newvolid;
6900 $disk->{size
} = $size;
6905 sub get_running_qemu_version
{
6907 my $res = mon_cmd
($vmid, "query-version");
6908 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6911 sub qemu_use_old_bios_files
{
6912 my ($machine_type) = @_;
6914 return if !$machine_type;
6916 my $use_old_bios_files = undef;
6918 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6920 $use_old_bios_files = 1;
6922 my $version = PVE
::QemuServer
::Machine
::extract_version
($machine_type, kvm_user_version
());
6923 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6924 # load new efi bios files on migration. So this hack is required to allow
6925 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6926 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6927 $use_old_bios_files = !min_version
($version, 2, 4);
6930 return ($use_old_bios_files, $machine_type);
6933 sub get_efivars_size
{
6935 my $arch = get_vm_arch
($conf);
6936 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6937 die "uefi vars image '$ovmf_vars' not found\n" if ! -f
$ovmf_vars;
6938 return -s
$ovmf_vars;
6941 sub update_efidisk_size
{
6944 return if !defined($conf->{efidisk0
});
6946 my $disk = PVE
::QemuServer
::parse_drive
('efidisk0', $conf->{efidisk0
});
6947 $disk->{size
} = get_efivars_size
($conf);
6948 $conf->{efidisk0
} = print_drive
($disk);
6953 sub create_efidisk
($$$$$) {
6954 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6956 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6957 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6959 my $vars_size_b = -s
$ovmf_vars;
6960 my $vars_size = PVE
::Tools
::convert_size
($vars_size_b, 'b' => 'kb');
6961 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6962 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6964 qemu_img_convert
($ovmf_vars, $volid, $vars_size_b, undef, 0);
6965 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $volid, 3);
6967 return ($volid, $size/1024);
6970 sub vm_iothreads_list
{
6973 my $res = mon_cmd
($vmid, 'query-iothreads');
6976 foreach my $iothread (@$res) {
6977 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6984 my ($conf, $drive) = @_;
6988 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6990 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6996 my $controller = int($drive->{index} / $maxdev);
6997 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6999 return ($maxdev, $controller, $controller_prefix);
7002 sub windows_version
{
7005 return 0 if !$ostype;
7009 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7011 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7013 } elsif ($ostype =~ m/^win(\d+)$/) {
7020 sub resolve_dst_disk_format
{
7021 my ($storecfg, $storeid, $src_volname, $format) = @_;
7022 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
7025 # if no target format is specified, use the source disk format as hint
7027 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7028 $format = qemu_img_format
($scfg, $src_volname);
7034 # test if requested format is supported - else use default
7035 my $supported = grep { $_ eq $format } @$validFormats;
7036 $format = $defFormat if !$supported;
7040 # NOTE: if this logic changes, please update docs & possibly gui logic
7041 sub find_vmstate_storage
{
7042 my ($conf, $storecfg) = @_;
7044 # first, return storage from conf if set
7045 return $conf->{vmstatestorage
} if $conf->{vmstatestorage
};
7047 my ($target, $shared, $local);
7049 foreach_storage_used_by_vm
($conf, sub {
7051 my $scfg = PVE
::Storage
::storage_config
($storecfg, $sid);
7052 my $dst = $scfg->{shared
} ? \
$shared : \
$local;
7053 $$dst = $sid if !$$dst || $scfg->{path
}; # prefer file based storage
7056 # second, use shared storage where VM has at least one disk
7057 # third, use local storage where VM has at least one disk
7058 # fall back to local storage
7059 $target = $shared // $local // 'local';
7065 my ($uuid, $uuid_str);
7066 UUID
::generate
($uuid);
7067 UUID
::unparse
($uuid, $uuid_str);
7071 sub generate_smbios1_uuid
{
7072 return "uuid=".generate_uuid
();
7078 mon_cmd
($vmid, 'nbd-server-stop');
7081 sub create_reboot_request
{
7083 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7084 or die "failed to create reboot trigger file: $!\n";
7088 sub clear_reboot_request
{
7090 my $path = "/run/qemu-server/$vmid.reboot";
7093 $res = unlink($path);
7094 die "could not remove reboot request for $vmid: $!"
7095 if !$res && $! != POSIX
::ENOENT
;
7100 # bash completion helper
7102 sub complete_backup_archives
{
7103 my ($cmdname, $pname, $cvalue) = @_;
7105 my $cfg = PVE
::Storage
::config
();
7109 if ($cvalue =~ m/^([^:]+):/) {
7113 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7116 foreach my $id (keys %$data) {
7117 foreach my $item (@{$data->{$id}}) {
7118 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7119 push @$res, $item->{volid
} if defined($item->{volid
});
7126 my $complete_vmid_full = sub {
7129 my $idlist = vmstatus
();
7133 foreach my $id (keys %$idlist) {
7134 my $d = $idlist->{$id};
7135 if (defined($running)) {
7136 next if $d->{template
};
7137 next if $running && $d->{status
} ne 'running';
7138 next if !$running && $d->{status
} eq 'running';
7147 return &$complete_vmid_full();
7150 sub complete_vmid_stopped
{
7151 return &$complete_vmid_full(0);
7154 sub complete_vmid_running
{
7155 return &$complete_vmid_full(1);
7158 sub complete_storage
{
7160 my $cfg = PVE
::Storage
::config
();
7161 my $ids = $cfg->{ids
};
7164 foreach my $sid (keys %$ids) {
7165 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7166 next if !$ids->{$sid}->{content
}->{images
};
7173 sub complete_migration_storage
{
7174 my ($cmd, $param, $current_value, $all_args) = @_;
7176 my $targetnode = @$all_args[1];
7178 my $cfg = PVE
::Storage
::config
();
7179 my $ids = $cfg->{ids
};
7182 foreach my $sid (keys %$ids) {
7183 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, $targetnode, 1);
7184 next if !$ids->{$sid}->{content
}->{images
};