diff --git a/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php b/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php index b1715e787..c21a6865f 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php +++ b/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php @@ -200,7 +200,7 @@ foreach ($vms as $vm) { echo "" : "' style='display:none'>"); echo ""; echo ""; - echo ""; + echo ""; echo ""; /* Display VM disks */ @@ -213,7 +213,9 @@ foreach ($vms as $vm) { $boot= $arrDisk["boot order"]; $serial = $arrDisk["serial"]; if ($boot < 1) $boot = _('Not set'); - echo ""; + $reallocation = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($disk)." 2>/dev/null")); + if (!empty($reallocation)) $reallocationstr = "($reallocation)"; else $reallocationstr = ""; + echo ""; if ($state == 'shutoff') { echo " + + - +
",_('Disk devices'),"",_('Serial'),"",_('Bus'),"",_('Capacity'),"",_('Allocation'),"Boot Order
",_('Disk devices/Volume'),"",_('Serial'),"",_('Bus'),"",_('Capacity'),"",_('Allocation'),"Boot Order
$disk$serial$bus
$disk $reallocationstr$serial$bus"; echo "
"; diff --git a/emhttp/plugins/dynamix.vm.manager/include/VMajax.php b/emhttp/plugins/dynamix.vm.manager/include/VMajax.php index 6ef653bad..178f5570f 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/VMajax.php +++ b/emhttp/plugins/dynamix.vm.manager/include/VMajax.php @@ -399,7 +399,7 @@ case 'disk-create': if (!is_dir($dir)) mkdir($dir); // determine the actual disk if user share is being used $dir = transpose_user_path($dir); - @exec("chattr +C -R ".escapeshellarg($dir)." >/dev/null"); + #@exec("chattr +C -R ".escapeshellarg($dir)." >/dev/null"); $strLastLine = exec("qemu-img create -q -f ".escapeshellarg($driver)." ".escapeshellarg($disk)." ".escapeshellarg($size)." 2>&1", $out, $status); $arrResponse = empty($status) ? ['success' => true] diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php index 153181ed6..847077d9b 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php @@ -79,7 +79,7 @@ $folder = transpose_user_path($folder); - @shell_exec("chattr +C -R " . escapeshellarg($folder) . " &>/dev/null"); + #@shell_exec("chattr +C -R " . escapeshellarg($folder) . " &>/dev/null"); return true; } @@ -208,6 +208,7 @@ $return_value = 0; } else { $strImgRawLocationPath = $strImgPath; + if (!empty($disk['storage']) && !empty($disk['select']) && $disk['select'] == 'auto' && $disk['storage'] != "default") $disk['select'] = $disk['storage']; 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); @@ -1043,6 +1044,8 @@ function domain_new($config) { + # Set storage for disks. + foreach ($config['disk'] as $i => $disk) { $config['disk'][$i]['storage'] = $config['template']['storage'];} // attempt to create all disk images if needed $diskcount = 0; if (!empty($config['disk'])) { @@ -1963,6 +1966,20 @@ return false; } + function nvram_rename($uuid,$newuuid) { + // rename backup OVMF VARS if this domain had them + if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi.fd')) { + rename('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi.fd_backup', '/etc/libvirt/qemu/nvram/'.$newuuid.'_VARS-pure-efi.fd'); + return true; + } + if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi-tpm.fd')) { + rename('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi-tpm.fd_backup', '/etc/libvirt/qemu/nvram/'.$newuuid.'_VARS-pure-efi-tpm.fd'); + return true; + } + + return false; + } + function nvram_create_snapshot($uuid,$snapshotname) { // snapshot backup OVMF VARS if this domain had them if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi.fd')) { diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php index e9dc13f1a..8282bf84c 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php @@ -1610,7 +1610,9 @@ private static $encoding = 'UTF-8'; $dom = $lv->domain_get_info($res); $state = $lv->domain_state_translate($dom['state']); $vmxml = $lv->domain_get_xml($res) ; - file_put_contents("/tmp/cloningxml" ,$vmxml) ; + file_put_contents("/tmp/cloningxml" ,$vmxml) ; ## Remove before stable. + $storage = $lv->_get_single_xpath_result($vm, '//domain/metadata/*[local-name()=\'vmtemplate\']/@storage'); + if (empty($storage)) $storage = "default" ; # if VM running shutdown. Record was running. if ($state != 'shutoff') {write("addLog\0".htmlspecialchars(_("Shuting down $vm current $state"))); $arrResponse = $lv->domain_destroy($vm) ; } # Wait for shutdown? @@ -1666,7 +1668,7 @@ private static $encoding = 'UTF-8'; $file_clone[$diskid]["target"] = $config["disk"][$diskid]["new"] ; } - $clonedir = $domain_cfg['DOMAINDIR'].$clone ; + if ($storage == "default") $clonedir = $domain_cfg['DOMAINDIR'].$clone ; else $clonedir = str_replace('/mnt/user/', "/mnt/$storage/", $domain_cfg['DOMAINDIR']).$clone; if (!is_dir($clonedir)) { mkdir($clonedir,0777,true) ; chown($clonedir, 'nobody'); @@ -1680,13 +1682,13 @@ private static $encoding = 'UTF-8'; $target = $disk['target'] ; $source = $disk['source'] ; if ($target == $source) { write("addLog\0".htmlspecialchars(_("New image file is same as old"))); return( false) ; } - $sourcerealdisk = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($source)." 2>/dev/null")); - $reptgt = str_replace('/mnt/user/', "/mnt/$sourcerealdisk/", $target); - $repsrc = str_replace('/mnt/user/', "/mnt/$sourcerealdisk/", $source); + if ($storage == "default") $sourcerealdisk = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($source)." 2>/dev/null")); else $sourcerealdisk = $storage; + $reptgt = str_replace('/mnt/user/', "/mnt/$sourcerealdisk/", $target); + $repsrc = str_replace('/mnt/user/', "/mnt/$sourcerealdisk/", $source); $cmdstr = "cp --reflink=always '$repsrc' '$reptgt'" ; if ($reflink == true) { $refcmd = $cmdstr ; } else {$refcmd = false; } - $cmdstr = "rsync -ahPIXS --out-format=%f --info=flist0,misc0,stats0,name1,progress2 '$source' '$target'" ; + $cmdstr = "rsync -ahPIXS --out-format=%f --info=flist0,misc0,stats0,name1,progress2 '$repsrc' '$reptgt'" ; $error = execCommand_nchan_clone($cmdstr,$target,$refcmd) ; if (!$error) { write("addLog\0".htmlspecialchars("Image copied failed.")); return( false) ; } } @@ -1695,7 +1697,7 @@ private static $encoding = 'UTF-8'; write("addLog\0".htmlspecialchars("Creating new XML $clone")); $xml = $lv->config_to_xml($config, true) ; - file_put_contents("/tmp/clonexml" ,$xml) ; + file_put_contents("/tmp/clonexml" ,$xml) ; ## Remove before stable. $rtn = $lv->domain_define($xml) ; return($rtn) ; @@ -1841,6 +1843,8 @@ private static $encoding = 'UTF-8'; $res = $lv->get_domain_by_name($vm); $dom = $lv->domain_get_info($res); $state = $lv->domain_state_translate($dom['state']); + $storage = $lv->_get_single_xpath_result($vm, '//domain/metadata/*[local-name()=\'vmtemplate\']/@storage'); + if (empty($storage)) $storage = "default" ; #Get disks for --diskspec $disks =$lv->get_disk_stats($vm) ; @@ -1852,16 +1856,23 @@ private static $encoding = 'UTF-8'; foreach($disks as $disk) { $file = $disk["file"] ; $pathinfo = pathinfo($file) ; - $filenew = $pathinfo["dirname"].'/'.$pathinfo["filename"].'.'.$name.'qcow2' ; + $dirpath = $pathinfo["dirname"]; + if ($storage == "default") { + $dirpath = $pathinfo["dirname"]; + } else { + $storagelocation = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($file)." 2>/dev/null")); + $dirpath= str_replace('/mnt/user/', "/mnt/$storagelocation/", $dirpath); + } + $filenew = $dirpath.'/'.$pathinfo["filename"].'.'.$name.'qcow2' ; $diskspec .= " --diskspec '".$disk["device"]."',snapshot=external,file='".$filenew."'" ; $capacity = $capacity + $disk["capacity"] ; } - $dirpath = $pathinfo["dirname"] ; + #get memory $mem = $lv->domain_get_memory_stats($vm) ; $memory = $mem[6] ; - if ($memorysnap = "yes") $memspec = ' --memspec "'.$pathinfo["dirname"].'/memory'.$name.'.mem",snapshot=external' ; else $memspec = "" ; + if ($memorysnap = "yes") $memspec = ' --memspec "'.$dirpath.'/memory'.$name.'.mem",snapshot=external' ; else $memspec = "" ; $cmdstr = "virsh snapshot-create-as '$vm' --name '$name' $snapshotdesc --atomic" ; @@ -1874,7 +1885,7 @@ private static $encoding = 'UTF-8'; } #Check free space. - $dirfree = disk_free_space($pathinfo["dirname"]) ; + $dirfree = disk_free_space($dirpath) ; $capacity *= 1 ; @@ -1883,8 +1894,8 @@ private static $encoding = 'UTF-8'; #Copy nvram if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_create_snapshot($lv->domain_get_uuid($vm),$name) ; - $xmlfile = $pathinfo["dirname"]."/".$name.".running" ; - file_put_contents("/tmp/xmltst", "$xmlfile" ) ; + $xmlfile = $dirpath."/".$name.".running" ; + file_put_contents("/tmp/xmltst", "$xmlfile" ) ;## Remove before stable. if ($state == "running") exec("virsh dumpxml '$vm' > ".escapeshellarg($xmlfile),$outxml,$rtnxml) ; $output= [] ; @@ -1943,7 +1954,9 @@ private static $encoding = 'UTF-8'; } } $xml = custom::createXML('domain',$xmlobj)->saveXML(); + if (!strpos($xml,'domain_define($xml); + file_put_contents("/tmp/xmlrevert", "$xml" ) ;## Remove before stable. if ($new) $arrResponse = ['success' => true] ; else $arrResponse = ['error' => $lv->get_last_error()] ; @@ -1978,13 +1991,14 @@ private static $encoding = 'UTF-8'; $xml = file_get_contents($xmlfile) ; $xmlobj = custom::createArray('domain',$xml) ; $xml = custom::createXML('domain',$xmlobj)->saveXML(); + if (!strpos($xml,'domain_define($xml) ; # Restore Memory. $makerun = true ; if ($makerun == true) exec("virsh restore ".escapeshellarg($memoryfile)) ; - #exec("virsh restore $memoryfile") ; } #Delete Metadata only. if ($actionmeta == "yes") { @@ -2027,8 +2041,6 @@ private static $encoding = 'UTF-8'; $reversed = array_reverse($output) ; $snaps[$vm][$rev] = $reversed ; $pathinfo = pathinfo($file) ; - #$filenew = $pathinfo["dirname"].'/'.$pathinfo["filename"].'.'.$name.'qcow2' ; - #$diskspec .= " --diskspec ".$disk["device"].",snapshot=external,file=".$filenew ; $capacity = $capacity + $disk["capacity"] ; } diff --git a/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php b/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php index a0449ef80..7f5be035b 100644 --- a/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php +++ b/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php @@ -41,7 +41,8 @@ 'template' => [ 'name' => $strSelectedTemplate, 'icon' => $arrAllTemplates[$strSelectedTemplate]['icon'], - 'os' => $arrAllTemplates[$strSelectedTemplate]['os'] + 'os' => $arrAllTemplates[$strSelectedTemplate]['os'], + 'storage' => "default" ], 'domain' => [ 'name' => $strSelectedTemplate, @@ -216,11 +217,15 @@ } } } - + $newuuid = $uuid; + $olduuid = $uuid; // construct updated config if (isset($_POST['xmldesc'])) { // XML view $xml = $_POST['xmldesc']; + $arrExistingConfig = custom::createArray('domain',$xml); + $newuuid = $arrExistingConfig['uuid'] ; + $xml = str_replace($olduuid,$newuuid,$xml); } else { // form view if ($error = create_vdisk($_POST) === false) { @@ -239,6 +244,7 @@ $lv->nvram_backup($uuid); $lv->domain_undefine($dom); $lv->nvram_restore($uuid); + if ($newuuid != $olduuid) $lv->nvram_rename($olduuid,$newuuid); $new = $lv->domain_define($xml); if ($new) { $lv->domain_set_autostart($new, $newAutoStart); @@ -295,6 +301,7 @@ + @@ -319,6 +326,66 @@ +
+ + + +
_(Override Storage Location)_: +
+
+

Specify the overide storage pool for VM. This option allows you to specify the physical pool/disk used to store the disk images and snapshot data. + Default will follow standard processing and store images in the default location for the share defined in the settings. + A pool/disk(Volume) will be the location for images if the default is overridden. +

+
+ +
_(vDisk Size)_: @@ -835,7 +904,7 @@
_(vDisk Size)_: diff --git a/emhttp/plugins/dynamix/include/SmartInfo.php b/emhttp/plugins/dynamix/include/SmartInfo.php index 995e27a38..280604bb8 100644 --- a/emhttp/plugins/dynamix/include/SmartInfo.php +++ b/emhttp/plugins/dynamix/include/SmartInfo.php @@ -229,10 +229,10 @@ case "stop": exec("smartctl -X $type ".escapeshellarg("/dev/$port")); break; case "update": - if ($disk["transport"] == "scsi") { + if ($disk["transport"] == "scsi" || $disk["transport"] == "nvme") { $progress = exec("smartctl -n standby -l selftest $type ".escapeshellarg("/dev/$port")."|grep -Pom1 '\d+%'"); if ($progress) { - echo " "._('self-test in progress').", ".(100-substr($progress,0,-1))."% "._('complete').""; + if ($disk["transport"] == "nvme") echo " "._('self-test in progress').", ".(substr($progress,0,-1))."% "._('complete').""; else echo " "._('self-test in progress').", ".(100-substr($progress,0,-1))."% "._('complete').""; break; } } else { @@ -243,7 +243,8 @@ case "update": } } if ($disk["transport"] == "scsi") $result = trim(exec("smartctl -n standby -l selftest $type ".escapeshellarg("/dev/$port")."|grep -m1 '^# 1'|cut -c24-50")); - else $result = trim(exec("smartctl -n standby -l selftest $type ".escapeshellarg("/dev/$port")."|grep -m1 '^# 1'|cut -c26-55")); + else if ($disk["transport"] == "nvme") $result = trim(exec("smartctl -n standby -l selftest $type ".escapeshellarg("/dev/$port")."|grep -m1 '^ 0'|cut -c24-50")); + else $result = trim(exec("smartctl -n standby -l selftest $type ".escapeshellarg("/dev/$port")."|grep -m1 '^# 1'|cut -c26-55")); if (!$result) { $spundown = $disk['spundown'] ? "Device spundown, spinup to get information" : "No self-tests logged on this disk" ; echo ""._($spundown)."";