From 9b208814dd2c5a81e2237017ad156941ee8b48de Mon Sep 17 00:00:00 2001 From: bergware Date: Sun, 9 Feb 2025 15:36:44 +0100 Subject: [PATCH 01/14] Update create_network_ini --- sbin/create_network_ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sbin/create_network_ini b/sbin/create_network_ini index 645aa1a37..fedd2c773 100755 --- a/sbin/create_network_ini +++ b/sbin/create_network_ini @@ -241,15 +241,15 @@ if [[ -z $interface || "eth0 br0 bond0 wlan0" =~ $interface ]]; then # find management interface [[ -e /sys/class/net/bond0 ]] && dev=bond0 || dev=eth0 [[ -e /sys/class/net/br0 ]] && dev=br0 - IPv4=$(ip -br -4 addr show $dev scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') - IPv6=$(ip -br -6 addr show $dev scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') + IPv4=$(ip -4 -br addr show $dev scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') + IPv6=$(ip -6 -br addr show $dev scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') # show current IP assignment [[ -n $IPv4 ]] && echo " IPv4 address: $IPv4" >>/etc/issue || echo " IPv4 address: not set" >>/etc/issue [[ -n $IPv6 ]] && echo " IPv6 address: $IPv6" >>/etc/issue || echo " IPv6 address: not set" >>/etc/issue if [[ -e /sys/class/net/wlan0 ]]; then echo "Wireless network:" >>/etc/issue - IPv4=$(ip -br -4 addr show wlan0 scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') - IPv6=$(ip -br -6 addr show wlan0 scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') + IPv4=$(ip -4 -br addr show wlan0 scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') + IPv6=$(ip -6 -br addr show wlan0 scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') [[ -n $IPv4 ]] && echo " IPv4 address: $IPv4" >>/etc/issue || echo " IPv4 address: not set" >>/etc/issue [[ -n $IPv6 ]] && echo " IPv6 address: $IPv6" >>/etc/issue || echo " IPv6 address: not set" >>/etc/issue fi From 8b4832ce4d2f3fb8556cbeb3eb50af55e976f0c7 Mon Sep 17 00:00:00 2001 From: bergware Date: Sun, 9 Feb 2025 15:43:48 +0100 Subject: [PATCH 02/14] rc.nginx add wireless connection as management port --- etc/rc.d/rc.nginx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/etc/rc.d/rc.nginx b/etc/rc.d/rc.nginx index ff32d0b50..5c75917f5 100755 --- a/etc/rc.d/rc.nginx +++ b/etc/rc.d/rc.nginx @@ -30,6 +30,7 @@ CERTPATH="$SSL/certs/certificate_bundle.pem" TSCERTPATH="$SSL/certs/ts_bundle.pem" MYSERVERS="/boot/config/plugins/dynamix.my.servers/myservers.cfg" DEFAULTS="/etc/default/nginx" +SYSTEM="/sys/class/net" # Load defaults # Defines NGINX_CUSTOMFA for custom Content-Security-Policy frame-ancestors url @@ -531,9 +532,15 @@ build_ssl(){ LANMDNS=${LANNAME}${LOCAL_TLD:+.$LOCAL_TLD} # fetch LAN IP address (read management interface eth0) - sed -n '/^\[eth0\]$/,/^TYPE/p' $NETWORK_INI >$NETWORK_INI.eth0 - LANIP=$(scan IPADDR:0 $NETWORK_INI.eth0); - LANIP6=$(scan IPADDR6:0 $NETWORK_INI.eth0); + [[ -e $SYSTEM/bond0 ]] && DEV=bond0 || DEV=eth0 + [[ -e $SYSTEM/br0 ]] && DEV=br0 + LANIP=$(ip -4 -br addr show $DEV scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') + LANIP6=$(ip -6 -br addr show $DEV scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') + + # try wireless connection if no IP address on interface eth0 + [[ -z $LANIP && -e $SYSTEM/wlan0 ]] && LANIP=$(ip -4 -br addr show wlan0 scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') + [[ -z $LANIP6 && -e $SYSTEM/wlan0 ]] && LANIP6=$(ip -6 -br addr show wlan0 scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') + rm -f $NETWORK_INI.eth0 # regenerate self-signed cert if local TLD changes */ From 09bc746e6c7b2fa034d6914c4841568c10f11627 Mon Sep 17 00:00:00 2001 From: bergware Date: Sun, 9 Feb 2025 15:45:22 +0100 Subject: [PATCH 03/14] rc.nginx remove unnecessary code --- etc/rc.d/rc.nginx | 2 -- 1 file changed, 2 deletions(-) diff --git a/etc/rc.d/rc.nginx b/etc/rc.d/rc.nginx index 5c75917f5..6ce029b6c 100755 --- a/etc/rc.d/rc.nginx +++ b/etc/rc.d/rc.nginx @@ -541,8 +541,6 @@ build_ssl(){ [[ -z $LANIP && -e $SYSTEM/wlan0 ]] && LANIP=$(ip -4 -br addr show wlan0 scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') [[ -z $LANIP6 && -e $SYSTEM/wlan0 ]] && LANIP6=$(ip -6 -br addr show wlan0 scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') - rm -f $NETWORK_INI.eth0 - # regenerate self-signed cert if local TLD changes */ SELFCERTPATH=$SSL/certs/${LANNAME}_unraid_bundle.pem [[ -f $SELFCERTPATH ]] && ! acceptable_selfcert && rm -f $SELFCERTPATH From a1e0672d444d28891076694ff45af693d7352483 Mon Sep 17 00:00:00 2001 From: bergware Date: Sun, 9 Feb 2025 16:55:32 +0100 Subject: [PATCH 04/14] Revamped VM page styling --- .../dynamix.vm.manager/include/VMedit.php | 56 +- .../dynamix.vm.manager/include/libvirt.php | 1005 ++-- .../include/libvirt_helpers.php | 13 +- .../dynamix.vm.manager/sheets/AddVM.css | 25 +- .../dynamix.vm.manager/sheets/UpdateVM.css | 25 +- .../templates/Custom.form.php | 4220 ++++++++--------- 6 files changed, 2468 insertions(+), 2876 deletions(-) diff --git a/emhttp/plugins/dynamix.vm.manager/include/VMedit.php b/emhttp/plugins/dynamix.vm.manager/include/VMedit.php index 9417b6cb4..cd0768870 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/VMedit.php +++ b/emhttp/plugins/dynamix.vm.manager/include/VMedit.php @@ -1,6 +1,6 @@
'/plugins/dynamix.vm.manager/templates/images/', - "$docroot/boot/config/plugins/dynamix.vm.manager/templates/images/*.png" => '/boot/config/plugins/dynamix.vm.manager/templates/images/' - ]; - foreach ($arrImagePaths as $strGlob => $strIconURLBase) { - foreach (glob($strGlob) as $png_file) { - echo '

'.basename($png_file,'.png').'

'; - } + $arrImagePaths = [ + "$docroot/plugins/dynamix.vm.manager/templates/images/*.png" => '/plugins/dynamix.vm.manager/templates/images/', + "$docroot/boot/config/plugins/dynamix.vm.manager/templates/images/*.png" => '/boot/config/plugins/dynamix.vm.manager/templates/images/' + ]; + foreach ($arrImagePaths as $strGlob => $strIconURLBase) { + foreach (glob($strGlob) as $png_file) { + echo '

'.basename($png_file,'.png').'

'; } + } ?>
+ + + + _(Autostart)_: + + > + + - - - - - -
_(Autostart)_:
>

If you want this VM to start with the array, set this to yes.

'.parse_file("$docroot/plugins/dynamix.vm.manager/templates/{$arrLoad['form']}",false))?>
- @@ -167,18 +168,17 @@ function isinlineXMLMode() { return ($.cookie('vmmanager_inline_mode') == 'show'); } -function hidexml(checked) -{ +function hidexml(checked) { var form = document.getElementById("vmform"); // Replace "yourFormId" with the actual ID of your form - var xmlElements = form.getElementsByClassName("xml"); - if (checked == 0) xmldisplay = "none"; else xmldisplay = ""; - // Unhide each element - for (var i = 0; i < xmlElements.length; i++) { - xmlElements[i].style.display = xmldisplay; // Setting to empty string will revert to default style -} + var xmlElements = form.getElementsByClassName("xml"); + if (checked == 0) xmldisplay = "none"; else xmldisplay = ""; + // Unhide each element + for (var i = 0; i < xmlElements.length; i++) { + xmlElements[i].style.display = xmldisplay; // Setting to empty string will revert to default style + } } -$(function() { +$(function(){ $('.autostart').switchButton({ on_label: "_(Yes)_", off_label: "_(No)_", diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php index c28842002..7eb612a88 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php @@ -19,17 +19,19 @@ class Libvirt { private $dominfos = []; private $enabled = false; - function Libvirt($uri = false, $login = false, $pwd = false, $debug=false) { - if ($debug) + function Libvirt($uri=false, $login=false, $pwd=false, $debug=false) { + if ($debug) { $this->set_logfile($debug); + } if ($uri != false) { $this->enabled = $this->connect($uri, $login, $pwd); } } - function __construct($uri = false, $login = false, $pwd = false, $debug=false) { - if ($debug) + function __construct($uri=false, $login=false, $pwd=false, $debug=false) { + if ($debug) { $this->set_logfile($debug); + } if ($uri != false) { $this->enabled = $this->connect($uri, $login, $pwd); } @@ -45,18 +47,16 @@ class Libvirt { } function set_logfile($filename) { - if (!libvirt_logfile_set($filename,10000)) - return $this->_set_last_error(); + if (!libvirt_logfile_set($filename,10000)) return $this->_set_last_error(); return true; } function get_capabilities() { $tmp = libvirt_connect_get_capabilities($this->conn); - return ($tmp) ? $tmp : $this->_set_last_error(); + return $tmp ?: $this->_set_last_error(); } function get_domain_capabilities($emulatorbin, $arch, $machine, $virttype, $xpath) { - #@conn [resource]: resource for connection #@emulatorbin [string]: optional path to emulator #@arch [string]: optional domain architecture @@ -65,48 +65,37 @@ class Libvirt { #@flags [int] : extra flags; not used yet, so callers should always pass 0 #@xpath [string]: optional xPath query to be applied on the result #Returns: : domain capabilities XML from the connection or FALSE for error - $tmp = libvirt_connect_get_domain_capabilities($this->conn, $emulatorbin, $arch, $machine, $virttype, 0, $xpath); - return ($tmp) ? $tmp : $this->_set_last_error(); + return $tmp ?: $this->_set_last_error(); } - function get_machine_types($arch = 'x86_64' /* or 'i686' */) { + function get_machine_types($arch='x86_64' /* or 'i686' */) { $tmp = libvirt_connect_get_machine_types($this->conn); - if (!$tmp) - return $this->_set_last_error(); - - if (empty($tmp[$arch])) { - return []; - } + if (!$tmp) return $this->_set_last_error(); + if (empty($tmp[$arch])) return []; return $tmp[$arch]; } function get_default_emulator() { $tmp = libvirt_connect_get_capabilities($this->conn, '//capabilities/guest/arch/domain/emulator'); - return ($tmp) ? $tmp : $this->_set_last_error(); + return $tmp ?: $this->_set_last_error(); } function set_folder_nodatacow($folder) { - if (!is_dir($folder)) { - return false; - } - + if (!is_dir($folder)) return false; $folder = transpose_user_path($folder); - #@shell_exec("chattr +C -R ".escapeshellarg($folder)." &>/dev/null"); return true; } - function create_disk_image($disk, $vmname = '', $diskid = 1) { + function create_disk_image($disk, $vmname='', $diskid=1) { $arrReturn = []; - if (!empty($disk['size'])) { $disk['size'] = str_replace(["KB","MB","GB","TB","PB"], ["K","M","G","T","P"], strtoupper($disk['size'])); } if (empty($disk['driver'])) { $disk['driver'] = 'raw'; } - // if new is a folder then // if existing then // create folder 'new/vmname' @@ -114,47 +103,35 @@ class Libvirt { // if doesn't exist then // create folder 'new' // create image file as new/vdisk[1-x].xxx - // if new is a file then // if existing then // nothing to do // if doesn't exist then // create folder dirname('new') if needed // create image file as new --> if size is specified - if (!empty($disk['new'])) { - if (is_file($disk['new']) || is_block($disk['new'])) { - $disk['image'] = $disk['new']; - } + if (is_file($disk['new']) || is_block($disk['new'])) $disk['image'] = $disk['new']; } - if (!empty($disk['image'])) { // Use existing disk image - if (is_block($disk['image'])) { // Valid block device, return as-is return $disk; } - if (is_file($disk['image'])) { $json_info = getDiskImageInfo($disk['image']); $disk['driver'] = $json_info['format']; - if (!empty($disk['size'])) { //TODO: expand disk image if size param is larger } - return $disk; } - $disk['new'] = $disk['image']; } - if (!empty($disk['new'])) { // Create new disk image $strImgFolder = $disk['new']; $strImgPath = ''; - if (strpos($strImgFolder, '/dev/') === 0) { // ERROR invalid block device $arrReturn = [ @@ -162,7 +139,6 @@ class Libvirt { ]; return $arrReturn; } - if (empty($disk['size'])) { // ERROR invalid disk size $arrReturn = [ @@ -170,20 +146,16 @@ class Libvirt { ]; return $arrReturn; } - $path_parts = pathinfo($strImgFolder); if (empty($path_parts['extension'])) { // 'new' is a folder - if (substr($strImgFolder, -1) != '/') { $strImgFolder .= '/'; } - if (is_dir($strImgFolder)) { // 'new' is a folder and already exists, append vmname folder $strImgFolder .= preg_replace('((^\.)|\/|(\.$))', '_', $vmname).'/'; } - // create folder if needed if (!is_dir($strImgFolder)) { #mkdir($strImgFolder, 0777, true); @@ -191,16 +163,11 @@ class Libvirt { #chown($strImgFolder, 'nobody'); #chgrp($strImgFolder, 'users'); } - $this->set_folder_nodatacow($strImgFolder); - $strExt = ($disk['driver'] == 'raw') ? 'img' : $disk['driver']; - $strImgPath = $strImgFolder.'vdisk'.$diskid.'.'.$strExt; - } else { // 'new' is a file - // create parent folder if needed if (!is_dir($path_parts['dirname'])) { #mkdir($path_parts['dirname'], 0777, true); @@ -208,13 +175,10 @@ class Libvirt { #chown($path_parts['dirname'], 'nobody'); #chgrp($path_parts['dirname'], 'users'); } - $this->set_folder_nodatacow($path_parts['dirname']); - $strExt = ($disk['driver'] == 'raw') ? 'img' : $disk['driver']; $strImgPath = $path_parts['dirname'].'/vdisk'.$diskid.'.'.$strExt; } - if (is_file($strImgPath)) { $json_info = getDiskImageInfo($strImgPath); $disk['driver'] = $json_info['format']; @@ -225,7 +189,6 @@ class Libvirt { if (!empty($disk['select']) && (!in_array($disk['select'], ['auto', 'manual'])) && (is_dir('/mnt/'.$disk['select']))) { // Force qemu disk creation to happen directly on either cache/disk1/disk2 ect based on dropdown selection $strImgRawLocationPath = str_replace('/mnt/user/', '/mnt/'.$disk['select'].'/', $strImgPath); - // create folder if needed $strImgRawLocationParent = dirname($strImgRawLocationPath); if (!is_dir($strImgRawLocationParent)) { @@ -234,29 +197,22 @@ class Libvirt { #chown($strImgRawLocationParent, 'nobody'); #chgrp($strImgRawLocationParent, 'users'); } - $this->set_folder_nodatacow($strImgRawLocationParent); } - $strLastLine = exec("qemu-img create -q -f ".escapeshellarg($disk['driver'])." ".escapeshellarg($strImgRawLocationPath)." ".escapeshellarg($disk['size'])." 2>&1", $output, $return_value); - if (is_file($strImgPath)) { chmod($strImgPath, 0777); chown($strImgPath, 'nobody'); chgrp($strImgPath, 'users'); } } - if ($return_value != 0) { - // ERROR during image creation, return message to user $arrReturn = [ 'error' => "Error creating disk image '".$strImgPath."': ".$strLastLine, 'error_output' => $output ]; - } else { - // Success! $arrReturn = [ 'image' => $strImgPath, @@ -280,13 +236,12 @@ class Libvirt { if (!empty($disk['discard'])) { $arrReturn['discard'] = $disk['discard']; } - } } return $arrReturn; } - function config_to_xml($config,$vmclone = false) { + function config_to_xml($config, $vmclone=false) { $domain = $config['domain']; $media = $config['media']; $nics = $config['nic']; @@ -302,7 +257,6 @@ class Libvirt { $template = $config['template']; $clocks = $config['clock']; $evdevs = $config['evdev']; - $type = $domain['type']; $name = $domain['name']; $mem = $domain['mem']; @@ -315,7 +269,6 @@ class Libvirt { $emulator = '/usr/local/sbin/qemu'; $arch = $domain['arch']; $pae = ($arch == 'i686') ? '' : ''; - $loader = ''; $swtpm = ''; $osbootdev = ''; @@ -330,7 +283,6 @@ class Libvirt { // Delete OVMF-TPM VARS for this VM if found unlink('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi-tpm.fd'); } - $loader = "/usr/share/qemu/ovmf-x64/OVMF_CODE-pure-efi.fd /etc/libvirt/qemu/nvram/".$uuid."_VARS-pure-efi.fd"; if ($domain['usbboot'] == 'Yes') $osbootdev = ""; @@ -345,17 +297,14 @@ class Libvirt { // Delete OVMF VARS for this VM if found unlink('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi.fd'); } - $loader = "/usr/share/qemu/ovmf-x64/OVMF_CODE-pure-efi-tpm.fd /etc/libvirt/qemu/nvram/".$uuid."_VARS-pure-efi-tpm.fd"; - $swtpm = " "; if ($domain['usbboot'] == 'Yes') $osbootdev = ""; } } - $metadata = ''; if (!empty($template)) { $metadata .= ""; @@ -366,21 +315,17 @@ class Libvirt { $metadata .= ""; $metadata .= ""; } - $vcpus = $domain['vcpus']; $vcpupinstr = ''; - if (!empty($domain['vcpu']) && is_array($domain['vcpu'])) { $vcpus = count($domain['vcpu']); foreach($domain['vcpu'] as $i => $vcpu) { $vcpupinstr .= ""; } } - $intCores = $vcpus; $intThreads = 1; $intCPUThreadsPerCore = 1; - $cpumode = ''; $cpucache = ''; $cpufeatures = ''; @@ -392,10 +337,8 @@ class Libvirt { if (!empty($domain['cpumode']) && $domain['cpumode'] == 'host-passthrough') { $cpumode .= "mode='host-passthrough'"; $cpucache = ""; - // detect if the processor is hyperthreaded: $intCPUThreadsPerCore = max(intval(shell_exec('/usr/bin/lscpu | grep \'Thread(s) per core\' | awk \'{print $4}\'')), 1); - // detect if the processor is AMD + multithreaded, and if so, enable topoext cpu feature if ($intCPUThreadsPerCore > 1) { $strCPUInfo = file_get_contents('/proc/cpuinfo'); @@ -403,76 +346,66 @@ class Libvirt { $cpufeatures .= ""; } } - // even amount of cores assigned and cpu is hyperthreaded: pass that info along to the cpu section below if ($intCPUThreadsPerCore > 1 && ($vcpus % $intCPUThreadsPerCore == 0)) { $intCores = $vcpus / $intCPUThreadsPerCore; $intThreads = $intCPUThreadsPerCore; } - if (!empty($domain['cpumigrate'])) $cpumigrate = " migratable='".$domain['cpumigrate']."'"; } # #Skylake-Client-noTSX-IBRS - $cpustr = " $cpucache $cpufeatures - - {$vcpus} - + + {$vcpus} + $vcpupinstr - "; - + "; $usbmode = 'usb3'; if (!empty($domain['usbmode'])) { $usbmode = $domain['usbmode']; } - $ctrl = ''; switch ($usbmode) { - case 'usb3': - $ctrl = " -
+ case 'usb3': + $ctrl = " +
"; - break; - - case 'usb3-qemu': - $ctrl = " -
+ break; + case 'usb3-qemu': + $ctrl = " +
"; - break; - - case 'usb2': - $ctrl = " -
+ break; + case 'usb2': + $ctrl = " +
- -
+ +
- -
+ +
- -
+ +
"; - break; + break; } - /* if ($os_type == "windows") $hypervclock = ""; else $hypervclock = ""; - $clock = " $hypervclock "; - $hyperv = ''; if ($domain['hyperv'] == 1 && $os_type == "windows") { $hyperv = " @@ -481,29 +414,27 @@ class Libvirt { "; - $clock = " "; } */ - $clock = ""; foreach ($clocks as $clockname => $clockvalues) { switch ($clockname){ - case "rtc": - if ($clockvalues['present'] == "yes") $clock .= ""; - break; - case "pit": - if ($clockvalues['present'] == "yes") $clock .= ""; - break; - case "hpet": - $clock .= ""; - break; - case "hypervclock": - $clock .= ""; - break; + case "rtc": + if ($clockvalues['present'] == "yes") $clock .= ""; + break; + case "pit": + if ($clockvalues['present'] == "yes") $clock .= ""; + break; + case "hpet": + $clock .= ""; + break; + case "hypervclock": + $clock .= ""; + break; } } $hyperv = ""; @@ -513,7 +444,6 @@ class Libvirt { "; - if ($clocks['hypervclock']['present'] == "yes") { $hyperv .= ""; } @@ -523,7 +453,6 @@ class Libvirt { # "; } $clock .= ""; - $usbstr = ''; if (!empty($usb)) { foreach($usb as $i => $v){ @@ -535,13 +464,11 @@ class Libvirt { if (isset($v["startupPolicy"]) && $vmclone ) { if ($v["startupPolicy"] == "optional" ) $startupPolicy = 'startupPolicy="optional"'; else $startupPolicy = ''; } - $usbstr .= " "; - if (!empty($usbboot[$v]) && !$vmclone ) { $usbstr .= ""; } @@ -551,20 +478,16 @@ class Libvirt { $usbstr .= ""; } } - $arrAvailableDevs = []; foreach (range('a', 'z') as $letter) { $arrAvailableDevs['hd'.$letter] = 'hd'.$letter; } - $needSCSIController = false; - //media settings $bus = "ide"; if ($machine_type == 'q35'){ $bus = "sata"; } - $mediastr = ''; if (!empty($media['cdrom'])) { unset($arrAvailableDevs['hda']); @@ -582,9 +505,8 @@ class Libvirt { $mediaboot - "; + "; } - $driverstr = ''; if (!empty($media['drivers']) && $os_type == "windows") { unset($arrAvailableDevs['hdb']); @@ -597,33 +519,27 @@ class Libvirt { - "; + "; } - //disk settings $diskstr = ''; $diskcount = 0; if (!empty($disks)) { - // force any hard drives to start with hdc, hdd, hde, etc unset($arrAvailableDevs['hda']); unset($arrAvailableDevs['hdb']); - foreach ($disks as $i => $disk) { if (!empty($disk['image']) | !empty($disk['new']) ) { //TODO: check if image/new is a block device $diskcount++; - if (!empty($disk['new'])) { if (is_file($disk['new']) || is_block($disk['new'])) { $disk['image'] = $disk['new']; } } - if (!empty($disk['image'])) { if (empty($disk['driver'])) { $disk['driver'] = 'raw'; - if (is_file($disk['image'])) { $json_info = getDiskImageInfo($disk['image']); $disk['driver'] = $json_info['format']; @@ -633,36 +549,28 @@ class Libvirt { if (empty($disk['driver'])) { $disk['driver'] = 'raw'; } - $strImgFolder = $disk['new']; $strImgPath = ''; - $path_parts = pathinfo($strImgFolder); if (empty($path_parts['extension'])) { // 'new' is a folder - if (substr($strImgFolder, -1) != '/') { $strImgFolder .= '/'; } - if (is_dir($strImgFolder)) { // 'new' is a folder and already exists, append domain name as child folder $strImgFolder .= preg_replace('((^\.)|\/|(\.$))', '_', $domain['name']).'/'; } - $strExt = ($disk['driver'] == 'raw') ? 'img' : $disk['driver']; $strImgPath = $strImgFolder.'vdisk'.$diskcount.'.'.$strExt; - } else { // 'new' is a file $strImgPath = $strImgFolder; } - if (is_file($strImgPath)) { $json_info = getDiskImageInfo($strImgPath); $disk['driver'] = $json_info['format']; } - $arrReturn = [ 'image' => $strImgPath, 'driver' => $disk['driver'] @@ -673,16 +581,12 @@ class Libvirt { if (!empty($disk['bus'])) { $arrReturn['bus'] = $disk['bus']; } - $disk = $arrReturn; } - $disk['bus'] = $disk['bus'] ?: 'virtio'; - if ($disk['bus'] == 'scsi') { $needSCSIController = true; } - if (empty($disk['dev']) || !in_array($disk['dev'], $arrAvailableDevs)) { $disk['dev'] = array_shift($arrAvailableDevs); } @@ -692,26 +596,19 @@ class Libvirt { if ($boot > 0) { $bootorder = ""; } - $readonly = ''; if (!empty($disk['readonly'])) { $readonly = ''; } - $strDevType = @filetype(realpath($disk['image'])); - if ($disk["serial"] != "") $serial = "".$disk["serial"].""; else $serial = ""; - $rotation_rate = ""; if ($disk['bus'] == "scsi" || $disk['bus'] == "sata" || $disk['bus'] == "ide" ) { if ($disk['rotation']) $rotation_rate = " rotation_rate='1' "; } - if ($strDevType == 'file' || $strDevType == 'block') { $strSourceType = ($strDevType == 'file' ? 'file' : 'dev'); - if (isset($disk['discard'])) $strDevUnmap = " discard=\"{$disk['discard']}\" "; else $strDevUnmap = " discard=\"ignore\" "; - $diskstr .= " @@ -719,47 +616,49 @@ class Libvirt { $bootorder $readonly $serial - "; + "; } } } } - $scsicontroller = ''; if ($needSCSIController) { $scsicontroller = ""; } - $netstr = ''; if (!empty($nics)) { foreach ($nics as $i => $nic) { - if (empty($nic['mac']) || empty($nic['network'])) { - continue; - } + if (empty($nic['mac']) || empty($nic['network'])) continue; $netmodel = $nic['model'] ?: 'virtio-net'; - - $net_res =$this->libvirt_get_net_res($this->conn, $nic['network']); - exec("ls --indicator-style=none /sys/class/net|grep -Po '^((vir)?br|vhost)[0-9]+(\.[0-9]+)?'",$br); - if ($nic["boot"] != NULL) $nicboot = ""; else $nicboot = ""; + $net_res = $this->libvirt_get_net_res($this->conn, $nic['network']); + exec("ls --indicator-style=none /sys/class/net | grep -Po '^((vir)?br|vhost|wlan)[0-9]+(\.[0-9]+)?'", $host); + $nicboot = $nic["boot"] != null ? "" : ""; if ($net_res) { - $netstr .= " + $netstr .= " + + + + $nicboot + "; + } elseif (in_array($nic['network'], $host)) { + if (preg_match('/^(vir)?br/', $nic['network'])) { + $netstr .= " - + $nicboot "; - } elseif (in_array($nic['network'], $br)) { - if (preg_match('/^(vir)?br/',$nic['network'])) { - $netstr .= " + } elseif ($nic['network'] == 'wlan0') { + $netstr .= " - + $nicboot "; } else { $netstr .= " - + $nicboot "; @@ -769,20 +668,16 @@ class Libvirt { } } } - $sharestr = ''; $memorybacking = json_decode($domain['memoryBacking'],true); - if (!empty($shares)) { foreach ($shares as $i => $share) { if (empty($share['source']) || empty($share['target']) || ($os_type == "windows" && $share["mode"] == "9p")) { continue; } - if ($share['mode'] == "virtiofs") { if (!isset($memorybacking['source'])) $memorybacking['source']["@attributes"]["type"] = "memfd"; if (!isset($memorybacking['access'])) $memorybacking['access']["@attributes"]["mode"] = "shared"; - $sharestr .= " @@ -800,7 +695,6 @@ class Libvirt { } } } - $pcidevs=''; $gpudevs_used=[]; $multidevices = []; #Load? @@ -818,16 +712,13 @@ class Libvirt { if (!empty($gpu['keymap'])) { if ($gpu['keymap'] != "none") $strKeyMap = "keymap='".$gpu['keymap']."'"; } - $passwdstr = ''; if (!empty($domain['password'])){ $passwdstr = "passwd='".htmlspecialchars($domain['password'], ENT_QUOTES | ENT_XML1)."'"; } - $strModelType = 'qxl'; if (!empty($gpu['model'])) { $strModelType = $gpu['model']; - if (!empty($domain['ovmf']) && $strModelType == 'vmvga') { // OVMF doesn't work with vmvga $strModelType = 'qxl'; @@ -836,23 +727,18 @@ class Libvirt { if (!empty($gpu['autoport'])) { $strAutoport = $gpu['autoport']; } else $strAutoport = "yes"; - if (!empty($gpu['protocol'])) { $strProtocol = $gpu['protocol']; } else $strProtocol = "vnc"; - if (!empty($gpu['wsport'])) { $strWSport = $gpu['wsport']; } else $strWSport = "-1"; - if (!empty($gpu['port'])) { $strPort = $gpu['port']; } else $strPort = "-1"; - if ($strAutoport == "yes") $strPort = $strWSport = "-1"; if (($gpu['copypaste'] == "yes") && ($strProtocol == "spice")) $vmrcmousemode = ""; else $vmrcmousemode = "" ; if ($strProtocol == "spice") $virtualaudio = "spice"; else $virtualaudio = "none"; - $strEGLHeadless = ""; $strAccel3d =""; if ($strModelType == "virtio3d") { @@ -865,55 +751,48 @@ class Libvirt { $strEGLHeadless = ''; $strAccel3d =""; }} - $strDisplayOptions = ""; if ($strModelType == "qxl") { if (empty($gpu['DisplayOptions'])) $gpu['DisplayOptions'] ="ram='65536' vram='16384' vgamem='16384' heads='1' primary='yes'"; $strDisplayOptions = $gpu['DisplayOptions']; } - $vmrc = " - - $vmrcmousemode + + $vmrcmousemode $strEGLHeadless