mirror of
https://github.com/unraid/webgui.git
synced 2026-02-24 03:10:39 -06:00
Merge pull request #1988 from SimonFair/vmdashusage-fix-
7.x Various VM Updates
This commit is contained in:
@@ -486,7 +486,7 @@ $(function() {
|
||||
<tbody id="kvm_list"><tr><td colspan='8'></td></tr></tbody>
|
||||
</table>
|
||||
|
||||
<input type="button" onclick="addVM()" id="btnAddVM" value="_(Add VM)_" style="display:none">
|
||||
<input type="button" onclick="addVM()" id="btnAddVM" value="_(Add VM)_/_(Templates)_" style="display:none">
|
||||
<input type="button" onclick="startAll()" value="_(Start All)_" style="display:none">
|
||||
<input type="button" onclick="stopAll()" value="_(Stop All)_" style="display:none">
|
||||
|
||||
|
||||
@@ -38,6 +38,16 @@ Markdown="false"
|
||||
if (strpos($strName,"User-") === false) $user = ""; else $user = ' class="user"';
|
||||
?>
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.filetree.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
|
||||
|
||||
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
|
||||
<script src="<?autov('/plugins/dynamix.vm.manager/javascript/dynamix.vm.manager.js')?>"></script>
|
||||
<script src="<?autov('/plugins/dynamix.vm.manager/javascript/vmmanager.js')?>"></script>
|
||||
<script src="<?autov('/webGui/javascript/jquery.filetree.js')?>" charset="utf-8"></script>
|
||||
|
||||
<div class="vmtemplate">
|
||||
<a href="/VMs/AddVM?template=<?=htmlspecialchars(urlencode($strName))?>">
|
||||
<span name="<?=htmlspecialchars($strName)?>" <?=$user?>><img src="/plugins/dynamix.vm.manager/templates/images/<?=htmlspecialchars($arrTemplate['icon'])?>" title="<?=htmlspecialchars($strName)?>"></span>
|
||||
@@ -46,7 +56,9 @@ Markdown="false"
|
||||
</div>
|
||||
<? endforeach; ?>
|
||||
<br>
|
||||
<center><button type='button' onclick='done()'>_(Cancel)_</button></center>
|
||||
<center><button type='button' onclick='done()'>_(Cancel)_</button>
|
||||
<button type='button' onclick='import_template()'>_(Import from file)_</button>
|
||||
<button type='button' onclick='$("#fileupload").click();'>_(Upload)_</button></center>
|
||||
<br>
|
||||
|
||||
<script>
|
||||
@@ -59,15 +71,200 @@ function confirmRemoveUserTemplate(template) {
|
||||
swal({title:"_(Proceed)_?",text:"Remove user template: " + template ,type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(p){if (p) removeUserTemplate(template); else refresh();});
|
||||
}
|
||||
|
||||
function saveUserTemplateFile(name,template) {
|
||||
$.post('/plugins/dynamix.vm.manager/include/VMajax.php',{action:'vm-template-save',name:name,template:template,replace:"no"},function($return){
|
||||
if ($return.success == false) {
|
||||
swal({title:"_(File exists)_?",text:"Replace file: " + name ,type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(No)_"},function(p){
|
||||
if (p) {
|
||||
$.post('/plugins/dynamix.vm.manager/include/VMajax.php',{action:'vm-template-save',name:name,template:template,replace:"yes"},function($return){
|
||||
if ($return.success == false) swal({title:"_(Error occured)_?",text:"Action error " + name + " " + $return.error ,type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(OK)_"});
|
||||
});
|
||||
}
|
||||
else {
|
||||
if ($return.success == false) swal({title:"_(Error occured)_?",text:"Action error " + name + " " + $return.error ,type:'error',html:true,showCancelButton:true,confirmButtonText:"_(OK)_"});
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function saveUserTemplateImport(name,template) {
|
||||
$.post('/plugins/dynamix.vm.manager/include/VMajax.php',{action:'vm-template-import',name:name,template:template,replace:"no"},function($return){
|
||||
if ($return.success == false) {
|
||||
swal({title:"_(File exists)_?",text:"Replace file: " + name.split(".")[0] ,type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(No)_"},function(p){
|
||||
if (p) {
|
||||
$.post('/plugins/dynamix.vm.manager/include/VMajax.php',{action:'vm-template-save',name:name,template:template,replace:"yes"},function($return){
|
||||
if ($return.success == false) swal({title:"_(Error occured)_?",text:"Action error " + name.split(".")[0] + " " + $return.error ,type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(OK)_"});
|
||||
if ($return.success == true) refresh();
|
||||
});
|
||||
}
|
||||
else {
|
||||
if ($return.success == false) swal({title:"_(Error occured)_?",text:"Action error " + name + " " + $return.error ,type:'error',html:true,showCancelButton:true,confirmButtonText:"_(OK)_"});
|
||||
};
|
||||
});
|
||||
}
|
||||
if ($return.success == true) refresh();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function downloadJSON(data, filename = 'data.json') {
|
||||
// Convert the data to a JSON string
|
||||
const jsonString = JSON.stringify(data, null, 2); // Beautify with 2 spaces
|
||||
// Create a Blob from the JSON string
|
||||
const blob = new Blob([jsonString], { type: 'application/json' });
|
||||
// Generate a temporary URL for the Blob
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Create a link element
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = filename; // Specify the file name
|
||||
|
||||
// Trigger the download by programmatically clicking the link
|
||||
link.click();
|
||||
|
||||
// Clean up by revoking the object URL
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
function export_template(template){
|
||||
const templatejson = <?=json_encode($ut)?>;
|
||||
var json = templatejson[template];
|
||||
var box = $("#dialogWindow");
|
||||
box.html($("#templateexport").html());
|
||||
box.find('#target').attr('value',template+".json");
|
||||
box.find('#target2').attr('value',"/mnt/").fileTreeAttach(null,null,function(path){
|
||||
box.find('#target2').val(path).change();
|
||||
});
|
||||
box.dialog({
|
||||
title: "_(Select File)_",
|
||||
height: 530,
|
||||
width: 900,
|
||||
resizable: false,
|
||||
modal: true,
|
||||
buttons: {
|
||||
"_(Save)_": function(){
|
||||
var target = box.find('#target');
|
||||
if (target.length) target = target.val(); else target = '';
|
||||
var target2 = box.find('#target2');
|
||||
if (target2.length) target2 = target2.val(); else target2 = '';
|
||||
box.find('#target').prop('disabled',true);
|
||||
box.find('#target2').prop('disabled',true);
|
||||
saveUserTemplateFile(target2+target,json);
|
||||
box.dialog('close');
|
||||
},
|
||||
"_(Cancel)_": function(){
|
||||
box.dialog('close');
|
||||
},
|
||||
"_(Download)_": function(){
|
||||
downloadJSON(json,template+'.json');
|
||||
box.dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogStyle();
|
||||
}
|
||||
|
||||
function import_template(){
|
||||
var box = $("#dialogWindow");
|
||||
box.html($("#templateimport").html());
|
||||
box.find('#targetimp').attr('value',"/mnt").fileTreeAttach(null,null,function(path){
|
||||
box.find('#targetimp').val(path).change();
|
||||
});
|
||||
box.dialog({
|
||||
title: "_(Select File)_",
|
||||
height: 530,
|
||||
width: 900,
|
||||
resizable: false,
|
||||
modal: true,
|
||||
buttons: {
|
||||
"_(Import)_": function(){
|
||||
var targetimp = box.find('#targetimp');
|
||||
if (targetimp.length) targetimp = targetimp.val(); else targetimp = '';
|
||||
box.find('#targetimp').prop('disabled',true);
|
||||
saveUserTemplateImport(targetimp,"*file");
|
||||
box.dialog('close');
|
||||
},
|
||||
"_(Cancel)_": function(){
|
||||
box.dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogStyle();
|
||||
}
|
||||
|
||||
function dialogStyle() {
|
||||
$('.ui-dialog-titlebar-close').css({'display':'none'});
|
||||
$('.ui-dialog-title').css({'text-align':'center','width':'100%','font-size':'1.8rem'});
|
||||
$('.ui-dialog-content').css({'padding-top':'15px','vertical-align':'bottom'});
|
||||
$('.ui-button-text').css({'padding':'0px 5px'});
|
||||
}
|
||||
|
||||
function exportTemplate(template) {
|
||||
$.post('/plugins/dynamix.vm.manager/include/VMajax.php',{action:'vm-template-export',template:template},function(){
|
||||
refresh();});
|
||||
}
|
||||
|
||||
function uploadFile(files,index,start,time) {
|
||||
var file = files[0];
|
||||
var blob = file;
|
||||
reader.onloadend = function(e){
|
||||
uploadedData = JSON.parse(e.target.result);
|
||||
//alert('File uploaded successfully. Click "Process JSON" to proceed.');
|
||||
saveUserTemplateImport(file.name,uploadedData);
|
||||
};
|
||||
reader.readAsText(blob);
|
||||
}
|
||||
|
||||
function startUpload(files) {
|
||||
if (files.length==0) return;
|
||||
reader = new FileReader();
|
||||
//window.onbeforeunload = function(e){return '';};
|
||||
uploadFile(files);
|
||||
}
|
||||
|
||||
var sortableHelper = function(e,ui){
|
||||
var child = ui.next();
|
||||
if (child.is(':visible')) child.addClass('unhide').hide();
|
||||
ui.children().each(function(){$(this).width($(this).width());});
|
||||
return ui;
|
||||
};
|
||||
|
||||
$(function(){
|
||||
$('div.vmtemplate').each(function(){
|
||||
var templatename = $(this).find('span').attr('name');
|
||||
$(this).find('span.user').append('<i class="fa fa-trash bin" title="_(Remove User Template)_" onclick="confirmRemoveUserTemplate("' + templatename + '");return false"></i>');
|
||||
$(this).find('span.user').append('<br><i class="fa fa-external-link-square export" title="_(Export User Template)_" onclick="export_template("' + templatename + '");return false"></i>');
|
||||
$(this).hover(function(){$(this).find('i.bin').show();},function(){$(this).find('i.bin').hide();});
|
||||
$(this).hover(function(){$(this).find('i.export').show();},function(){$(this).find('i.export').hide();});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
|
||||
i.bin{display:none;font-size:1.8rem;position:absolute;margin-left:12px}
|
||||
</style>
|
||||
i.export{display:none;font-size:1.8rem;position:left;margin-left:1px}
|
||||
</style>
|
||||
|
||||
<div id="dialogWindow"></div>
|
||||
<div id="iframe-popup"></div>
|
||||
|
||||
<div id="templateexport" class="template">
|
||||
<dl>
|
||||
<dt>_(Save File Name)_:</dt>
|
||||
<dd><input type="text" id="target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="iso"></dd>
|
||||
<dt>_(Save Path)_:</dt>
|
||||
<dd><input type="text" id="target2" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="iso"></dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div id="templateimport" class="template">
|
||||
<dl>
|
||||
<dt>_(File for import)_:</dt>
|
||||
<dd><input type="text" id="targetimp" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="json"></dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
|
||||
<input hidden type="file" id="fileupload" value="" onchange="startUpload(this.files)"
|
||||
@@ -78,18 +78,22 @@ foreach ($vms as $vm) {
|
||||
$vmrcurl = '';
|
||||
$graphics = '';
|
||||
$virtual = false ;
|
||||
if (isset($arrConfig['gpu'][0]['model'])) {$vrtdriver=" "._("Driver").strtoupper(":{$arrConfig['gpu'][0]['model']} "); $vrtmodel =$arrConfig['gpu'][0]['model'];} else $vrtdriver = "";
|
||||
if (isset($arrConfig['gpu'][0]['render']) && $vrtmodel == "virtio3d") {
|
||||
if (isset($arrConfig['gpu'][0]['render']) && $arrConfig['gpu'][0]['render'] == "auto") $vrtdriver .= "<br>"._("RenderGPU").":"._("Auto"); else $vrtdriver .= "<br>"._("RenderGPU").":{$arrValidGPUDevices[$arrConfig['gpu'][0]['render']]['name']}";
|
||||
}
|
||||
if ($vmrcport > 0) {
|
||||
$wsport = $lv->domain_get_ws_port($res);
|
||||
$vmrcprotocol = $lv->domain_get_vmrc_protocol($res);
|
||||
if ($vmrcprotocol == "vnc") $vmrcscale = "&resize=scale"; else $vmrcscale = "";
|
||||
$vmrcurl = autov('/plugins/dynamix.vm.manager/'.$vmrcprotocol.'.html',true).$vmrcscale.'&autoconnect=true&host='._var($_SERVER,'HTTP_HOST');
|
||||
if ($vmrcprotocol == "spice") $vmrcurl .= '&vmname='. urlencode($vm) .'&port=/wsproxy/'.$vmrcport.'/'; else $vmrcurl .= '&port=&path=/wsproxy/'.$wsport.'/';
|
||||
$graphics = strtoupper($vmrcprotocol).":".$vmrcport."\n";
|
||||
$graphics = strtoupper($vmrcprotocol).':'._($auto)."$vrtdriver\n";
|
||||
$virtual = true ;
|
||||
} elseif ($vmrcport == -1 || $autoport) {
|
||||
$vmrcprotocol = $lv->domain_get_vmrc_protocol($res);
|
||||
if ($autoport == "yes") $auto = "auto"; else $auto="manual";
|
||||
$graphics = strtoupper($vmrcprotocol).':'._($auto)."\n";
|
||||
$graphics = strtoupper($vmrcprotocol).':'._($auto)."$vrtdriver\n";
|
||||
$virtual = true ;
|
||||
}
|
||||
if (!empty($arrConfig['gpu'])) {
|
||||
|
||||
@@ -872,6 +872,50 @@ case 'vm-template-remove':
|
||||
$arrResponse = ['success' => true];
|
||||
break;
|
||||
|
||||
case 'vm-template-save':
|
||||
$template = $_REQUEST['template'];
|
||||
$name = $_REQUEST['name'];
|
||||
$replace = $_REQUEST['replace'];
|
||||
|
||||
if (is_file($name) && $replace == "no"){
|
||||
$arrResponse = ['success' => false, 'error' => _("File exists.")];
|
||||
} else {
|
||||
$error = file_put_contents($name,json_encode($template));
|
||||
if ($error !== false) $arrResponse = ['success' => true];
|
||||
else {
|
||||
$arrResponse = ['success' => false, 'error' => _("File write failed.")];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'vm-template-import':
|
||||
$template = $_REQUEST['template'];
|
||||
$name = $_REQUEST['name'];
|
||||
$replace = $_REQUEST['replace'];
|
||||
$templateslocation = "/boot/config/plugins/dynamix.vm.manager/savedtemplates.json";
|
||||
|
||||
if ($template==="*file") {
|
||||
$template=json_decode(file_get_contents($name));
|
||||
}
|
||||
|
||||
$namepathinfo = pathinfo($name);
|
||||
$template_name = $namepathinfo['filename'];
|
||||
|
||||
if (is_file($templateslocation)){
|
||||
$ut = json_decode(file_get_contents($templateslocation),true) ;
|
||||
if (isset($ut[$template_name]) && $replace == "no"){
|
||||
$arrResponse = ['success' => false, 'error' => _("Template exists.")];
|
||||
} else {
|
||||
$ut[$template_name] = $template;
|
||||
$error = file_put_contents($templateslocation,json_encode($ut,JSON_PRETTY_PRINT));;
|
||||
if ($error !== false) $arrResponse = ['success' => true];
|
||||
else {
|
||||
$arrResponse = ['success' => false, 'error' => _("Tempalte file write failed.")];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$arrResponse = ['error' => _('Unknown action')." '$action'"];
|
||||
break;
|
||||
|
||||
@@ -55,6 +55,22 @@
|
||||
return ($tmp) ? $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
|
||||
#@machine [string]: optional machine type
|
||||
#@virttype [string]: optional virtualization type
|
||||
#@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();
|
||||
}
|
||||
|
||||
|
||||
function get_machine_types($arch = 'x86_64' /* or 'i686' */) {
|
||||
$tmp = libvirt_connect_get_machine_types($this->conn);
|
||||
|
||||
@@ -383,6 +399,10 @@
|
||||
$cpucache = '';
|
||||
$cpufeatures = '';
|
||||
$cpumigrate = '';
|
||||
$cpucheck = '';
|
||||
$cpumatch = '' ;
|
||||
$cpucustom = '' ;
|
||||
$cpufallback = '' ;
|
||||
if (!empty($domain['cpumode']) && $domain['cpumode'] == 'host-passthrough') {
|
||||
$cpumode .= "mode='host-passthrough'";
|
||||
$cpucache = "<cache mode='passthrough'/>";
|
||||
@@ -406,6 +426,8 @@
|
||||
|
||||
if (!empty($domain['cpumigrate'])) $cpumigrate = " migratable='".$domain['cpumigrate']."'" ;
|
||||
}
|
||||
#<cpu mode='custom' match='exact' check='partial'>
|
||||
#<model fallback='allow'>Skylake-Client-noTSX-IBRS</model>
|
||||
|
||||
$cpustr = "<cpu $cpumode $cpumigrate>
|
||||
<topology sockets='1' cores='{$intCores}' threads='{$intThreads}'/>
|
||||
@@ -847,6 +869,25 @@
|
||||
if (($gpu['copypaste'] == "yes") && ($strProtocol == "spice")) $vmrcmousemode = "<mouse mode='server'/>" ; else $vmrcmousemode = "" ;
|
||||
if ($strProtocol == "spice") $virtualaudio = "spice" ; else $virtualaudio = "none" ;
|
||||
|
||||
$strEGLHeadless = "";
|
||||
$strAccel3d ="";
|
||||
if ($strModelType == "virtio3d") {
|
||||
$strModelType = "virtio";
|
||||
if (!isset($gpu['render'])) $gpu['render'] = "auto";
|
||||
if ($gpu['render'] == "auto") {
|
||||
$strEGLHeadless = '<graphics type="egl-headless"><gl enable="yes"/></graphics>';
|
||||
$strAccel3d = "<acceleration accel3d='yes'/>";
|
||||
} else {
|
||||
$strEGLHeadless = '<graphics type="egl-headless"><gl enable="yes" rendernode="/dev/dri/by-path/pci-0000:'.$gpu['render'].'-render"/></graphics>';
|
||||
$strAccel3d ="<acceleration accel3d='yes'/>";
|
||||
}}
|
||||
|
||||
$strDisplayOptions = "";
|
||||
if ($strModelType == "qxl") {
|
||||
if (empty($gpu['DisplayOptions'])) $gpu['DisplayOptions'] ="ram='65536' vram='16384' vgamem='16384' heads='1' primary='yes'";
|
||||
$strDisplayOptions = $gpu['DisplayOptions'];
|
||||
}
|
||||
|
||||
$vmrc = "<input type='tablet' bus='usb'/>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='keyboard' bus='ps2'/>
|
||||
@@ -854,8 +895,11 @@
|
||||
<listen type='address' address='0.0.0.0'/>
|
||||
$vmrcmousemode
|
||||
</graphics>
|
||||
$strEGLHeadless
|
||||
<video>
|
||||
<model type='$strModelType'/>
|
||||
<model type='$strModelType' $strDisplayOptions>
|
||||
$strAccel3d
|
||||
</model>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/>
|
||||
</video>
|
||||
<audio id='1' type='$virtualaudio'/>";
|
||||
@@ -2158,7 +2202,7 @@
|
||||
}
|
||||
|
||||
function domain_get_vnc_port($domain) {
|
||||
$tmp = $this->get_xpath($domain, '//domain/devices/graphics/@port', false);
|
||||
$tmp = $this->get_xpath($domain, '//domain/devices/graphics[@type="spice" or @type="vnc"]/@port', false);
|
||||
$var = (int)$tmp[0];
|
||||
unset($tmp);
|
||||
|
||||
@@ -2166,7 +2210,7 @@
|
||||
}
|
||||
|
||||
function domain_get_vmrc_autoport($domain) {
|
||||
$tmp = $this->get_xpath($domain, '//domain/devices/graphics/@autoport', false);
|
||||
$tmp = $this->get_xpath($domain, '//domain/devices/graphics[@type="spice" or @type="vnc"]/@autoport', false);
|
||||
$var = $tmp[0];
|
||||
unset($tmp);
|
||||
|
||||
@@ -2189,6 +2233,44 @@
|
||||
$var = $tmp[0];
|
||||
unset($tmp);
|
||||
|
||||
if ($var=="virtio") {
|
||||
$tmp = $this->get_xpath($domain, '//domain/devices/video/model/acceleration/@accel3d', false);
|
||||
if ($tmp[0] == "yes") $var = "virtio3d";
|
||||
unset($tmp);
|
||||
}
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
function domain_get_vnc_render($domain) {
|
||||
$tmp = $this->get_xpath($domain, '//domain/devices/graphics[@type="egl-headless"]/gl/@rendernode', false);
|
||||
if (!$tmp)
|
||||
return 'auto';
|
||||
|
||||
$var = $tmp[0];
|
||||
unset($tmp);
|
||||
|
||||
if (!str_contains($var,"pci")) $var = trim(shell_exec("udevadm info -q symlink -r $var"));
|
||||
$var = str_replace(['/dev/dri/by-path/pci-0000:','-render'],['',''],$var);
|
||||
return $var;
|
||||
}
|
||||
|
||||
function domain_get_vnc_display_options($domain) {
|
||||
$tmp = $this->get_xpath($domain, '//domain/devices/video/model/@heads', false);
|
||||
if (!$tmp)
|
||||
$heads=1;
|
||||
|
||||
$heads = $tmp[0];
|
||||
unset($tmp);
|
||||
|
||||
$tmp = $this->get_xpath($domain, '//domain/devices/video/model/@vram', false);
|
||||
if (!$tmp)
|
||||
$vram=16384/1024;
|
||||
|
||||
$vram = $tmp[0]/1024;
|
||||
unset($tmp);
|
||||
|
||||
$var = "H$heads.{$vram}M";
|
||||
return $var;
|
||||
}
|
||||
|
||||
@@ -2267,6 +2349,40 @@
|
||||
|
||||
return $var;
|
||||
}
|
||||
# <cpu mode='custom' match='exact' check='partial'>
|
||||
# <model fallback='allow'>Skylake-Client-noTSX-IBRS</model>
|
||||
|
||||
function domain_get_cpu_custom($domain) {
|
||||
$tmp = $this->get_xpath($domain, '//domain/cpu/@match', false);
|
||||
if (!$tmp)
|
||||
$tmp[0] = '';
|
||||
|
||||
$var['match'] = trim($tmp[0]);
|
||||
unset($tmp);
|
||||
|
||||
$tmp = $this->get_xpath($domain, '//domain/cpu/@check', false);
|
||||
if (!$tmp)
|
||||
$tmp[0] = '';
|
||||
|
||||
$var['check'] = trim($tmp[0]);
|
||||
unset($tmp);
|
||||
|
||||
$tmp = $this->get_xpath($domain, '//domain/cpu/model/@fallback', false);
|
||||
if (!$tmp)
|
||||
$tmp[0] = '';
|
||||
|
||||
$var['fallback'] = trim($tmp[0]);
|
||||
unset($tmp);
|
||||
|
||||
$tmp = $this->get_xpath($domain, '//domain/cpu/model', false);
|
||||
if (!$tmp)
|
||||
$tmp[0] = '';
|
||||
|
||||
$var['model'] = trim($tmp[0]);
|
||||
unset($tmp);
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
function domain_get_cpu_migrate($domain) {
|
||||
$tmp = $this->get_xpath($domain, '//domain/cpu/@migratable', false);
|
||||
|
||||
@@ -708,6 +708,55 @@ private static $encoding = 'UTF-8';
|
||||
] ;
|
||||
|
||||
|
||||
#<model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
|
||||
|
||||
$arrDisplayOptions = [
|
||||
"H1.16M" => [
|
||||
"text" => "1 Display 16Mb Memory",
|
||||
"qxlxml" => "ram='65536' vram='16384' vgamem='16384' heads='1' primary='yes'",
|
||||
],
|
||||
"H1.32M" => [
|
||||
"text" => "1 Display 32Mb Memory",
|
||||
"qxlxml" => "ram='65536' vram='32768' vgamem='32768' heads='1' primary='yes'",
|
||||
],
|
||||
"H1.64M" => [
|
||||
"text" => "1 Display 64Mb Memory",
|
||||
"qxlxml" => "ram='65536' vram='65536' vram64='65535' vgamem='65536' heads='1' primary='yes'",
|
||||
],
|
||||
"H1.128M" => [
|
||||
"text" => "1 Display 128Mb Memory",
|
||||
"qxlxml"=> "ram='65536' vram='131072' vram64='131072' vgamem='65536' heads='1' primary='yes'",
|
||||
],
|
||||
"H1.256M" => [
|
||||
"text" => "1 Display 256Mb Memory",
|
||||
"qxlxml" => "ram='65536' vram='262144' vram64='262144' vgamem='65536' heads='1' primary='yes'",
|
||||
],
|
||||
"H2.64M" => [
|
||||
"text" => "2 Displays 64Mb Memory",
|
||||
"qxlxml" => "ram='65536' vram='65536' vram64='65535' vgamem='65536' heads='2' primary='yes'",
|
||||
],
|
||||
"H2.128M" => [
|
||||
"text" => "2 Displays 128Mb Memory",
|
||||
"qxlxml" => "ram='65536' vram='131072'vram64='131072' vgamem='65536' heads='2' primary='yes'",
|
||||
],
|
||||
"H2.256M" => [
|
||||
"text" => "2 Displays 256Mb Memory",
|
||||
"qxlxml" => "ram='65536' vram='262144'vram64='262144' vgamem='65536' heads='2' primary='yes'",
|
||||
],
|
||||
"H4.64M" => [
|
||||
"text" => "4 Displays 64Mb Memory",
|
||||
"qxlxml" => "ram='65536' vram='65536' vram64='65535' vgamem='65536' heads='4' primary='yes'",
|
||||
],
|
||||
"H4.128M" => [
|
||||
"text" => "4 Displays 128Mb Memory",
|
||||
"qxlxml" => "ram='65536' vram='131072'vram64='131072' vgamem='65536' heads='4' primary='yes'",
|
||||
],
|
||||
"H4.256M" => [
|
||||
"text" => "4 Displays 256Mb Memory",
|
||||
"qxlxml"=> "ram='65536' vram='262144' vram64='262144' vgamem='65536' heads='4' primary='yes'",
|
||||
],
|
||||
];
|
||||
|
||||
// Read configuration file (guaranteed to exist)
|
||||
$domain_cfgfile = "/boot/config/domain.cfg";
|
||||
$domain_cfg = parse_ini_file($domain_cfgfile);
|
||||
@@ -866,6 +915,15 @@ private static $encoding = 'UTF-8';
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to get the boot_vga driver for this pci device
|
||||
$strBootVGA = '';
|
||||
if (is_file('/sys/bus/pci/devices/0000:' . $arrMatch['id'] . '/boot_vga') && $strClass == 'vga') {
|
||||
$strFileVal = file_get_contents('/sys/bus/pci/devices/0000:' . $arrMatch['id'] . '/boot_vga');
|
||||
if (!empty($strFileVal)) {
|
||||
$strBootVGA = trim($strFileVal);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up the vendor and product name
|
||||
$arrMatch['vendorname'] = sanitizeVendor($arrMatch['vendorname']);
|
||||
$arrMatch['productname'] = sanitizeProduct($arrMatch['productname']);
|
||||
@@ -880,6 +938,7 @@ private static $encoding = 'UTF-8';
|
||||
'productname' => $arrMatch['productname'],
|
||||
'class' => $strClass,
|
||||
'driver' => $strDriver,
|
||||
'bootvga' => $strBootVGA,
|
||||
'name' => $arrMatch['vendorname'] . ' ' . $arrMatch['productname'],
|
||||
'blacklisted' => $boolBlacklisted
|
||||
];
|
||||
@@ -1116,6 +1175,7 @@ private static $encoding = 'UTF-8';
|
||||
'cirrus' => 'Cirrus',
|
||||
'qxl' => 'QXL (best)',
|
||||
'virtio' => 'Virtio(2d)',
|
||||
'virtio3d' => 'Virtio(3d)',
|
||||
'vmvga' => 'vmvga'
|
||||
];
|
||||
|
||||
@@ -1269,6 +1329,8 @@ private static $encoding = 'UTF-8';
|
||||
'autoport' => $autoport,
|
||||
'copypaste' => $getcopypaste,
|
||||
'guest' => ['multi' => 'off' ],
|
||||
'render' => $lv->domain_get_vnc_render($res),
|
||||
'DisplayOptions' => $lv->domain_get_vnc_display_options($res),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1481,7 +1543,7 @@ private static $encoding = 'UTF-8';
|
||||
unset($old['devices']['input']);
|
||||
// preserve vnc/spice port settings
|
||||
// unset($new['devices']['graphics']['@attributes']['port'],$new['devices']['graphics']['@attributes']['autoport']);
|
||||
if (!$new['devices']['graphics']) unset($old['devices']['graphics']);
|
||||
unset($old['devices']['graphics']);
|
||||
if (!isset($new['devices']['graphics']['@attributes']['keymap']) && isset($old['devices']['graphics']['@attributes']['keymap'])) unset($old['devices']['graphics']['@attributes']['keymap']) ;
|
||||
// update parent arrays
|
||||
if (!$old['devices']['hostdev']) unset($old['devices']['hostdev']);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
@@ -0,0 +1,2 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
.vmtemplate{display:inline-block;width:80px;height:90px;margin-bottom:15px;margin-left:10px;text-align:center;vertical-align:top}
|
||||
.vmtemplate img{width:48px;height:48px}
|
||||
.vmtemplate p{text-align:center;margin-top:8px;line-height:12px}
|
||||
div.template,div#dialogWindow,input#upload{display:none}
|
||||
|
||||
@@ -102,7 +102,9 @@
|
||||
'keymap' => 'none',
|
||||
'port' => -1 ,
|
||||
'wsport' => -1,
|
||||
'copypaste' => 'no'
|
||||
'copypaste' => 'no',
|
||||
'render' => 'auto',
|
||||
'DisplayOptions' => ""
|
||||
]
|
||||
],
|
||||
'audio' => [
|
||||
@@ -464,9 +466,9 @@
|
||||
<select id="cpu" name="domain[cpumode]" class="cpu" title="_(define type of cpu presented to this vm)_">
|
||||
<?mk_dropdown_options(['host-passthrough' => _('Host Passthrough').' (' . $strCPUModel . ')', 'custom' => _('Emulated').' ('._('QEMU64').')'], $arrConfig['domain']['cpumode']);?>
|
||||
</select>
|
||||
<span class="advanced" id="domain_cpumigrate_text"<?=$migratehidden?>>_(Migratable)_:</span>
|
||||
<span class="advanced" id="domain_cpumigrate_text" <?=$migratehidden?>>_(Migratable)_:</span>
|
||||
|
||||
<select name="domain[cpumigrate]" id="domain_cpumigrate" <?=$migratehidden?> class="narrow" title="_(define if migratable)_">
|
||||
<select name="domain[cpumigrate]" id="domain_cpumigrate" <?=$migratehidden?> hidden class="narrow" title="_(define if migratable)_">
|
||||
<?
|
||||
echo mk_option($arrConfig['domain']['cpumigrate'], 'on', 'On');
|
||||
echo mk_option($arrConfig['domain']['cpumigrate'], 'off', 'Off') ;
|
||||
@@ -1159,8 +1161,8 @@
|
||||
|
||||
<?foreach ($arrConfig['gpu'] as $i => $arrGPU) {
|
||||
$strLabel = ($i > 0) ? appendOrdinalSuffix($i + 1) : '';
|
||||
|
||||
?>
|
||||
$bootgpuhidden = " hidden ";
|
||||
?>
|
||||
<table data-category="Graphics_Card" data-multiple="true" data-minimum="1" data-maximum="<?=count($arrValidGPUDevices)+1?>" data-index="<?=$i?>" data-prefix="<?=$strLabel?>">
|
||||
<tr>
|
||||
<td>_(Graphics Card)_:</td>
|
||||
@@ -1249,9 +1251,28 @@
|
||||
<tr class="<?if ($arrGPU['id'] != 'virtual') echo 'was';?>advanced vncmodel">
|
||||
<td>_(VM Console Video Driver)_:</td>
|
||||
<td>
|
||||
<select id="vncmodel" name="gpu[<?=$i?>][model]" class="narrow" title="_(video for VM Console)_">
|
||||
<select id="vncmodel" name="gpu[<?=$i?>][model]" class="narrow" title="_(video for VM Console)_" onchange="VMConsoleDriverChange(this)">
|
||||
<?mk_dropdown_options($arrValidVNCModels, $arrGPU['model']);?>
|
||||
</select>
|
||||
<?if ($arrGPU['model'] == "virtio3d") $vmcrender = "" ; else $vmcrender = " hidden ";?>
|
||||
<span id="vncrendertext" <?=$vncrender?>>_(Render GPU)_:</span>
|
||||
<select id="vncrender" name="gpu[<?=$i?>][render]">
|
||||
<?
|
||||
echo mk_option($arrGPU['render'], 'auto', _('Auto'));
|
||||
foreach($arrValidGPUDevices as $arrDev) {
|
||||
echo mk_option($arrGPU['render'], $arrDev['id'], $arrDev['name'].' ('.$arrDev['id'].')');
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<?$arrGPU['DisplayOptions'] = htmlentities($arrDisplayOptions[$arrGPU['DisplayOptions']]['qxlxml'],ENT_QUOTES);
|
||||
if ($arrGPU['model'] == "qxl") $vncdspopt = "" ; else $vncdspopt = " hidden ";?>
|
||||
<span id="vncdspopttext" <?=$vncdspopt?>>_(Display(s) and RAM)_:</span>
|
||||
<select id="vncdspopt" name="gpu[<?=$i?>][DisplayOptions]">
|
||||
<?
|
||||
foreach($arrDisplayOptions as $key => $value) {
|
||||
echo mk_option($arrGPU['DisplayOptions'], htmlentities($value['qxlxml'],ENT_QUOTES), _($value['text']));
|
||||
}?>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1274,6 +1295,10 @@
|
||||
<input type="text" name="gpu[<?=$i?>][rom]" autocomplete="off" spellcheck="false" data-pickcloseonfile="true" data-pickfilter="rom,bin" data-pickmatch="^[^.].*" data-pickroot="/mnt/" value="<?=htmlspecialchars($arrGPU['rom'])?>" placeholder="_(Path to ROM BIOS file)_ (_(optional)_)" title="_(Path to ROM BIOS file)_ (_(optional)_)" />
|
||||
</td>
|
||||
</tr>
|
||||
<?
|
||||
if ($arrValidGPUDevices[$arrGPU['id']]['bootvga'] == "1") $bootgpuhidden = "";
|
||||
?>
|
||||
<tr id="gpubootvga<?=$i?>" <?=$bootgpuhidden?>><td>_(Graphics ROM Needed?)_:</td><td><span class="orange-text"><i class="fa fa-warning"></i> _(GPU is primary adapater, vbios may be required.)_</span></td></tr>
|
||||
</table>
|
||||
<?if ($i == 0 || $i == 1) {?>
|
||||
<blockquote class="inline_help">
|
||||
@@ -1300,6 +1325,8 @@
|
||||
<p class="<?if ($arrGPU['id'] != 'virtual') echo 'was';?>advanced vncmodel">
|
||||
<b>Virtual Video Driver</b><br>
|
||||
If you wish to assign a different video driver to use for a VM Console connection, specify one here.
|
||||
QXL has an option of setting number of screens and vram.
|
||||
Virtio3d allows render device to be specified or auto.(This allow GPU to be used in a VM without passthru for 3D acceleration no screen output)
|
||||
</p>
|
||||
|
||||
<p class="vncpassword">
|
||||
@@ -1350,6 +1377,7 @@
|
||||
<input type="text" name="gpu[{{INDEX}}][rom]" autocomplete="off" spellcheck="false" data-pickcloseonfile="true" data-pickfilter="rom,bin" data-pickmatch="^[^.].*" data-pickroot="/mnt/" value="" placeholder="_(Path to ROM BIOS file)_ (_(optional)_)" title="_(Path to ROM BIOS file)_ (_(optional)_)" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="gpubootvga{{INDEX}}" hidden><td>_(Graphics ROM Needed?)_:</td><td><span class="orange-text"><i class="fa fa-warning"></i> _(GPU is primary adapater, vbios may be required.)_</span></td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
@@ -2084,6 +2112,31 @@ function AutoportChange(autoport) {
|
||||
}
|
||||
}
|
||||
|
||||
function VMConsoleDriverChange(driver) {
|
||||
if (driver.value != "virtio3d") {
|
||||
document.getElementById("vncrender").style.visibility="hidden";
|
||||
document.getElementById("vncrendertext").style.visibility="hidden";
|
||||
document.getElementById("vncrender").style.display="none";
|
||||
document.getElementById("vncrendertext").style.display="none";
|
||||
|
||||
} else {
|
||||
document.getElementById("vncrender").style.display="inline";
|
||||
document.getElementById("vncrender").style.visibility="visible";
|
||||
document.getElementById("vncrendertext").style.display="inline";
|
||||
document.getElementById("vncrendertext").style.visibility="visible";
|
||||
}
|
||||
if (driver.value != "qxl") {
|
||||
document.getElementById("vncdspopt").style.visibility="hidden";
|
||||
document.getElementById("vncdspopttext").style.visibility="hidden";
|
||||
|
||||
} else {
|
||||
document.getElementById("vncdspopt").style.display="inline";
|
||||
document.getElementById("vncdspopt").style.visibility="visible";
|
||||
document.getElementById("vncdspopttext").style.display="inline";
|
||||
document.getElementById("vncdspopttext").style.visibility="visible";
|
||||
}
|
||||
}
|
||||
|
||||
function ProtocolChange(protocol) {
|
||||
var autoport = document.getElementById("autoport").value ;
|
||||
if (autoport == "yes") {
|
||||
@@ -2392,6 +2445,7 @@ $(function() {
|
||||
}) ;
|
||||
|
||||
$("#vmform").on("change", ".gpu", function changeGPUEvent() {
|
||||
const ValidGPUs = <?=json_encode($arrValidGPUDevices);?>;
|
||||
var myvalue = $(this).val();
|
||||
var mylabel = $(this).children('option:selected').text();
|
||||
var myindex = $(this).closest('table').data('index');
|
||||
@@ -2403,6 +2457,28 @@ $(function() {
|
||||
slideDownRows($vnc_sections.not(isVMAdvancedMode() ? '.basic' : '.advanced'));
|
||||
var MultiSel = document.getElementById("GPUMultiSel0") ;
|
||||
MultiSel.disabled = true ;
|
||||
if (document.getElementById("vncmodel").value == "virtio3d") {
|
||||
$("#vncrender").show();
|
||||
$("#vncrendertext").show();
|
||||
} else {
|
||||
$("#vncrender").hide();
|
||||
$("#vncrendertext").hide();
|
||||
document.getElementById("vncrender").style.display="none";
|
||||
document.getElementById("vncrendertext").style.display="none";
|
||||
}
|
||||
if (document.getElementById("vncmodel").value == "qxl") {
|
||||
$("#vncdspopt").show();
|
||||
$("#vncdspopttext").show();
|
||||
document.getElementById("vncdspopt").style.display="inline";
|
||||
document.getElementById("vncdspopt").style.visibility="visible";
|
||||
document.getElementById("vncdspopttext").style.display="inline";
|
||||
document.getElementById("vncdspopttext").style.visibility="visible";
|
||||
} else {
|
||||
$("#vncdspopt").hide();
|
||||
$("#vncdspopttext").hide();
|
||||
document.getElementById("vncdspopt").style.display="none";
|
||||
document.getElementById("vncdspopttext").style.display="none";
|
||||
}
|
||||
} else {
|
||||
slideUpRows($vnc_sections);
|
||||
$vnc_sections.filter('.advanced').removeClass('advanced').addClass('wasadvanced');
|
||||
@@ -2411,8 +2487,13 @@ $(function() {
|
||||
}
|
||||
}
|
||||
|
||||
if (mylabel == "_(None)_") $("#gpubootvga"+myindex).hide();
|
||||
if (myvalue != "_(virtual)_" && myvalue != '' && myvalue != "_(nogpu)_") {
|
||||
if (ValidGPUs[myvalue].bootvga == "1") $("#gpubootvga"+myindex).show(); else $("#gpubootvga"+myindex).hide();
|
||||
}
|
||||
|
||||
$romfile = $(this).closest('table').find('.romfile');
|
||||
if (myvalue == 'virtual' || myvalue == '' || myvalue =="nogpu") {
|
||||
if (myvalue == '_(virtual)_' || myvalue == '' || myvalue =="_(nogpu)_") {
|
||||
slideUpRows($romfile.not(isVMAdvancedMode() ? '.basic' : '.advanced'));
|
||||
$romfile.filter('.advanced').removeClass('advanced').addClass('wasadvanced');
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user