Merge pull request #1750 from SimonFair/WebUI

Create WebUI option in VM Template.
This commit is contained in:
tom mortensen
2024-06-03 13:13:34 -07:00
committed by GitHub
9 changed files with 133 additions and 7 deletions

View File

@@ -1680,6 +1680,10 @@ For setting the console options to show on context menus. Web will show only inb
Virtual Manager Remote Viewer will only show the Remote Viewer option. Both will show both Web and Remote Viewer.
:end
:vms_rdpopt_help:
Adds option to menu to start RDP. RDP file is downloaded. You need to set browser to open when ready.
:end
:vms_usage_help:
Show metrics for CPU both guest and host percentage, memory, disk io and network io.
:end

View File

@@ -183,6 +183,14 @@ _(Console Options)_:
:vms_console_help:
_(Show RDP menu option)_:
: <select id="vmsrdpopt" name="RDPOPT">
<?=mk_option($domain_cfg['RDPOPT'], 'no', _('Dont show RDP option'))?>
<?=mk_option($domain_cfg['RDPOPT'], 'yes', _('Show RDP option'))?>
</select>
:vms_rdpopt_help:
_(Show VM Usage)_:
: <select id="vmusage" name="USAGE">
<?=mk_option($domain_cfg['USAGE'], 'N', _('Disabled'))?>

View File

@@ -72,6 +72,7 @@ foreach ($vms as $vm) {
$diskdesc = 'Current physical size: '.$lv->get_disk_capacity($res, true)."\nDefault snapshot type: $fstype";
}
$arrValidDiskBuses = getValidDiskBuses();
$WebUI = html_entity_decode($arrConfig['template']['webui']);
$vmrcport = $lv->domain_get_vnc_port($res);
$autoport = $lv->domain_get_vmrc_autoport($res);
$vmrcurl = '';
@@ -109,7 +110,8 @@ foreach ($vms as $vm) {
}
unset($dom);
if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web" ; else $vmrcconsole = $domain_cfg["CONSOLE"] ;
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm),addslashes($uuid),addslashes($template),$state,addslashes($vmrcurl),strtoupper($vmrcprotocol),addslashes($log),addslashes($fstype), $vmrcconsole,false);
if (!isset($domain_cfg["RDPOPT"])) $vmrcconsole .= ";no" ; else $vmrcconsole .= ";".$domain_cfg["RDPOPT"] ;
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s', '%s')\"", addslashes($vm),addslashes($uuid),addslashes($template),$state,addslashes($vmrcurl),strtoupper($vmrcprotocol),addslashes($log),addslashes($fstype), $vmrcconsole,false,addslashes(str_replace('"',"'",$WebUI)));
$kvm[] = "kvm.push({id:'$uuid',state:'$state'});";
switch ($state) {
case 'running':

View File

@@ -128,6 +128,20 @@ case 'domain-start-consoleRV':
$arrResponse['vvfile'] = $vvfile;
break;
case 'domain-consoleRDP':
requireLibvirt();
$dom = $lv->get_domain_by_name($domName);
$rdpvarray = array() ;
$myIP=get_vm_ip($dom);
if ($myIP == NULL) {$arrResponse['error'] = "No IP, guest agent not installed?"; break; }
$rdparray[] = "full address:s: $myIP\n";
#$rdparray[] = "administrative session:1\n";
if (!is_dir("/mnt/user/system/remoteviewer")) mkdir("/mnt/user/system/remoteviewer") ;
$rdpfile = "/mnt/user/system/remoteviewer/rv"._var($_SERVER,'HTTP_HOST').".$port.rdp" ;
file_put_contents($rdpfile,$rdparray) ;
$arrResponse['vvfile'] = $rdpfile;
break;
case 'domain-consoleRV':
requireLibvirt();
$dom = $lv->get_domain_by_name($domName);
@@ -146,6 +160,23 @@ case 'domain-consoleRV':
file_put_contents($vvfile,$vvarray) ;
$arrResponse['vvfile'] = $vvfile;
break;
case 'domain-openWebUI':
requireLibvirt();
$dom = $lv->get_domain_by_name($domName);
$WebUI = unscript(_var($_REQUEST,'vmrcurl'));
$myIP = get_vm_ip($dom);
if (strpos($WebUI,"[IP]") && $myIP == NULL) $arrResponse['error'] = "No IP, guest agent not installed?";
$WebUI = preg_replace("%\[IP\]%", $myIP, $WebUI);
$vmnamehypen = str_replace(" ","-",$domName);
$WebUI = preg_replace("%\[VMNAME\]%", $vmnamehypen, $WebUI);
if (preg_match("%\[PORT:(\d+)\]%", $WebUI, $matches)) {
$ConfigPort = $matches[1] ?? '';
$WebUI = preg_replace("%\[PORT:\d+\]%", $ConfigPort, $WebUI);
}
$arrResponse['vmrcurl'] = $WebUI;
break;
case 'domain-pause':
requireLibvirt();

View File

@@ -2765,4 +2765,30 @@ function qemu_log($vm,$m) {
file_put_contents("/var/log/libvirt/qemu/$vm.log",$m."\n",FILE_APPEND);
}
function get_vm_ip($dom) {
global $lv;
$myIP=null;
$gastate = getgastate($dom);
if ($gastate == "connected") {
$ip = $lv->domain_interface_addresses($dom, 1);
$gastate = getgastate($dom);
if ($gastate == "connected") {
$ip = $lv->domain_interface_addresses($dom, 1);
if ($ip != false) {
foreach ($ip as $arrIP) {
$ipname = $arrIP["name"];
if (preg_match('/^(lo|Loopback)/',$ipname)) continue; // omit loopback interface
$iplist = $arrIP["addrs"];
foreach ($iplist as $arraddr) {
$myIP= $arraddr["addr"];
if (preg_match('/^f[c-f]/',$myIP)) continue; // omit ipv6 private addresses
break 2;
}
}
}
}
}
return $myIP;
}
?>

View File

@@ -2,6 +2,10 @@ function displayconsole(url) {
window.open(url, '_blank', 'scrollbars=yes,resizable=yes');
}
function displayWebUI(url) {
window.open(url, '', 'scrollbars=yes,resizable=yes');
}
function downloadFile(source) {
var a = document.createElement('a');
a.setAttribute('href',source);
@@ -62,10 +66,30 @@ function ajaxVMDispatchconsoleRV(params, spin){
}
},'json');
}
function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, fstype="QEMU",console="web",usage=false){
function ajaxVMDispatchWebUI(params, spin){
if (spin) $('#vm-'+params['uuid']).parent().find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", params, function(data) {
if (data.error) {
swal({
title:_("Execution error"), html:true,
text:data.error, type:"error",
confirmButtonText:_('Ok')
},function(){
if (spin) setTimeout(spin+'()',500); else location=window.location.href;
});
} else {
if (spin) setTimeout(spin+'()',500); else location=window.location.href;
setTimeout('displayWebUI("'+data.vmrcurl+'")',500) ;
}
},'json');
}
function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, fstype="QEMU",consolein="web;no",usage=false,webui=""){
var opts = [];
var path = location.pathname;
var x = path.indexOf("?");
var consolesplit = consolein.split(";");
var console = consolesplit[0];
var rdpopt = consolesplit[1];
if (x!=-1) path = path.substring(0,x);
if (vmrcurl !== "" && state == "running") {
if (console == "web" || console == "both") {
@@ -81,7 +105,18 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, f
ajaxVMDispatchconsoleRV({action:"domain-consoleRV", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ;
}});
}
if (webui != "") {
opts.push({text:_("Open WebUI") , icon:"fa-globe", action:function(e) {
e.preventDefault();
ajaxVMDispatchWebUI({action:"domain-openWebUI", uuid:uuid, vmrcurl:webui}, "loadlist") ;
}});
}
if (rdpopt == "yes") {
opts.push({text:_("VM Remote Desktop Protocol(RDP)"), icon:"fa-desktop", action:function(e) {
e.preventDefault();
ajaxVMDispatchconsoleRV({action:"domain-consoleRDP", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ;
}});
}
opts.push({divider:true});
}
context.settings({right:false,above:false});

View File

@@ -357,6 +357,22 @@
</blockquote>
</div>
<table>
<tr class="advanced">
<td>_(WebUI)_:</td>
<td><input type="url" name="template[webui]" title="_(Web UI to start)_" placeholder="_(Web UI to start from menu)_ (_(optional)_)" value="<?=htmlspecialchars($arrConfig['template']['webui'])?>" /></td>
</tr>
</table>
<div class="advanced">
<blockquote class="inline_help">
<p>Specify a URL that for menu to start. Substution variables are
<br>[IP] IP address, this will take the first IP on the VM. Guest Agent must be installed for this to work.
<br>[PORT:XX] Port Number in XX.
<br>[VMNAME] VM Name will have spaces replaced with -
</p>
</blockquote>
</div>
<table>
<tr>
<?if (!$boolNew) $disablestorage = " disabled "; else $disablestorage = "";?>

View File

@@ -119,7 +119,9 @@ if ($_POST['vms']) {
if (empty($template)) $template = 'Custom';
$log = (is_file("/var/log/libvirt/qemu/$vm.log") ? "libvirt/qemu/$vm.log" : '');
if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web" ; else $vmrcconsole = $domain_cfg["CONSOLE"] ;
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log),addslashes($fstype), $vmrcconsole);
if (!isset($domain_cfg["RDPOPT"])) $vmrcconsole .= ";no" ; else $vmrcconsole .= ";".$domain_cfg["RDPOPT"] ;
$WebUI = html_entity_decode($arrConfig["template"]["webui"]);
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log),addslashes($fstype), $vmrcconsole,false,addslashes(str_replace('"',"'",$WebUI)));
$icon = $lv->domain_get_icon_url($res);
switch ($state) {
case 'running':
@@ -144,7 +146,7 @@ if ($_POST['vms']) {
echo "<span class='outer solid vms $status'><span id='vm-$uuid' $menu class='hand'>$image</span><span class='inner'>$vm<br><i class='fa fa-$shape $status $color'></i><span class='state'>"._($status)."</span></span></span>";
if ($state == "running") {
#Build VM Usage array.
$menuusage = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log),addslashes($fstype), $vmrcconsole,true);
$menuusage = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log),addslashes($fstype), $vmrcconsole,true,addslashes(str_replace('"',"'",$WebUI)));
$vmusagehtml[] = "<span class='outer solid vmsuse $status'><span id='vmusage-$uuid' $menuusage class='hand'>$image</span><span class='inner'>$vm<br><i class='fa fa-$shape $status $color'></i><span class='state'>"._($status)."</span></span>";
$vmusagehtml[] = "<br><br><span id='vmmetrics-gcpu-".$uuid."'>"._("Loading")."....</span>";
$vmusagehtml[] = "<br><span id='vmmetrics-hcpu-".$uuid."'>"._("Loading")."....</span>";

View File

@@ -285,12 +285,14 @@ function my_mkdir($dirname,$permissions = 0777,$recursive = false,$own = "nobody
$parent = str_replace('/mnt/user/', "/mnt/$realdisk/", $parent);
}
}
$fstype = trim(shell_exec(" stat -f -c '%T' $parent"));
$fstype = trim(shell_exec(" stat -f -c '%T' $parent"));
$rtncode = false;
switch ($fstype) {
case "zfs":
$zfsdataset = trim(shell_exec("zfs list -H -o name $parent")) ;
$zfsdataset .= str_replace($parent,"",$dirname);
if (strpos($zfsdataset,'/') !== false) $zfsdataset .= str_replace($parent,"",$dirname); else {
$zfsdataset .= str_replace("/mnt/$zfsdataset","",$dirname);
}
if ($recursive) $rtncode=exec("zfs create -p \"$zfsdataset\"");else $rtncode=exec("zfs create \"$zfsdataset\"");
if (!$rtncode) mkdir($dirname, $permissions, $recursive); else chmod($zfsdataset,$permissions);
break;