mirror of
https://github.com/unraid/webgui.git
synced 2026-01-16 14:39:57 -06:00
450 lines
17 KiB
Plaintext
450 lines
17 KiB
Plaintext
Menu="OtherSettings"
|
|
Title="VM Manager"
|
|
Icon="dynamix.vm.manager.png"
|
|
Markdown="false"
|
|
---
|
|
<?PHP
|
|
/* Copyright 2015, Lime Technology
|
|
* Copyright 2015, Derek Macias, Eric Schultz, Jon Panozzo.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License version 2,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*/
|
|
?>
|
|
<?
|
|
require_once('/usr/local/emhttp/plugins/dynamix.vm.manager/classes/libvirt.php');
|
|
require_once('/usr/local/emhttp/plugins/dynamix.vm.manager/classes/libvirt_helpers.php');
|
|
|
|
|
|
// Check for Intel VT-x (vmx) or AMD-V (svm) cpu virtualzation support
|
|
// If either kvm_intel or kvm_amd are loaded then Intel VT-x (vmx) or AMD-V (svm) cpu virtualzation support was found
|
|
$strLoadedModules = shell_exec("lsmod | grep '^kvm_\(amd\|intel\)'");
|
|
if (empty($strLoadedModules)) {
|
|
// Attempt to load either of the kvm modules to see if virtualzation hw is supported
|
|
exec('modprobe -a kvm_intel kvm_amd 2>/dev/null');
|
|
$strLoadedModules = shell_exec("lsmod | grep '^kvm_\(amd\|intel\)'");
|
|
if (!empty($strLoadedModules)) {
|
|
exec('modprobe -r kvm_intel kvm_amd 2>/dev/null');
|
|
} else {
|
|
?><p class="notice">Your hardware does not have Intel VT-x or AMD-V capability. This is required to create VMs in KVM. <a href="http://lime-technology.com/wiki/index.php/UnRAID_Manual_6#Hardware-Assisted_Virtualization_.28HVM.29" target="_blank">Click here to see the unRAID Wiki for more information</a></p><?php
|
|
exit;
|
|
}
|
|
}
|
|
|
|
|
|
$arrValidBridges = getNetworkBridges();
|
|
|
|
|
|
// Check for PCIE ACS capabilities
|
|
$boolACSEnabled = (strpos(file_get_contents('/proc/cmdline'), 'pcie_acs_override=') !== false);
|
|
|
|
// Check the /boot/syslinux/syslinux.cfg for the existance of pcie_acs_override=
|
|
$arrSyslinuxCfg = file('/boot/syslinux/syslinux.cfg');
|
|
$strCurrentLabel = '';
|
|
$boolACSInSyslinux = false;
|
|
|
|
foreach ($arrSyslinuxCfg as &$strSyslinuxCfg) {
|
|
if (stripos(trim($strSyslinuxCfg), 'label ') === 0) {
|
|
$strCurrentLabel = trim(str_ireplace('label ', '', $strSyslinuxCfg));
|
|
}
|
|
if (stripos($strSyslinuxCfg, 'append ') !== false) {
|
|
if (stripos($strSyslinuxCfg, 'pcie_acs_override=') !== false) {
|
|
// pcie_acs_override= was found
|
|
$boolACSInSyslinux = true;
|
|
}
|
|
|
|
// We just examine the first append line
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($boolACSEnabled != $boolACSInSyslinux) {
|
|
?><p class="notice">You must reboot for changes to take effect</p><?php
|
|
}
|
|
?>
|
|
<link type="text/css" rel="stylesheet" href="/plugins/dynamix.vm.manager/styles/dynamix.vm.manager.css">
|
|
<link type="text/css" rel="stylesheet" href="/webGui/styles/jquery.filetree.css">
|
|
<link type="text/css" rel="stylesheet" href="/webGui/styles/jquery.switchbutton.css">
|
|
<style>
|
|
body { -webkit-overflow-scrolling: touch;}
|
|
.errortext{color:#EF3D47;display:none;}
|
|
.fileTree {
|
|
width: 305px;
|
|
max-height: 150px;
|
|
overflow: scroll;
|
|
position: absolute;
|
|
z-index: 100;
|
|
display: none;
|
|
}
|
|
.basic{display:block;}
|
|
.advanced{display:none;white-space:nowrap;}
|
|
#winvirtio{display:none;}
|
|
#download_status {
|
|
margin-left: 5px;
|
|
color: #777;
|
|
display: none;
|
|
}
|
|
#download_button {
|
|
cursor: pointer;
|
|
margin-left: -2px;
|
|
color: #08C;
|
|
font-size: 1.4em;
|
|
display: none;
|
|
transform: translate(0px, 4px);
|
|
}
|
|
#download_button.fa-spin {
|
|
cursor: default;
|
|
color: #777;
|
|
}
|
|
#download_button span {
|
|
font-size: 12px;
|
|
font-family: arimo;
|
|
vertical-align: top;
|
|
}
|
|
</style>
|
|
<span class="status" style="margin-top: -10px;"><input type="checkbox" class="advancedview"></span>
|
|
<form id="settingsForm" markdown="1" method="POST" action="/update.php" target="progressFrame">
|
|
<input type="hidden" name="#file" value="<?=$domain_cfgfile;?>" />
|
|
|
|
<dl>
|
|
<dt>Enable VMs:</dt>
|
|
<dd>
|
|
<select id="SERVICE" name="SERVICE" class="narrow">
|
|
<?= mk_option($libvirt_service, 'disable', 'No'); ?>
|
|
<?= mk_option($libvirt_service, 'enable', 'Yes'); ?>
|
|
</select> <?if ($var['fsState'] != "Started"):?><span id="arraystopped"><i class="fa fa-warning icon warning"></i> <?=($libvirt_service=='enable')?'VMs will be available after Array is Started':'Apply to activate VMs after Array is Started'?></span><?endif;?>
|
|
</dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p>Stopping the VM Manager will first attempt to shutdown all running VMs. After 40 seconds, any remaining VM instances will be terminated.</p>
|
|
</blockquote>
|
|
|
|
<?if ($libvirt_running == 'yes'):?>
|
|
|
|
<div class="advanced">
|
|
<dl>
|
|
<dt>Libvirt version:</dt>
|
|
<dd><? $libvirt_info = libvirt_version('libvirt'); echo $libvirt_info['libvirt.major'].'.'.$libvirt_info['libvirt.minor'].'.'.$libvirt_info['libvirt.release']; ?></dd>
|
|
</dl>
|
|
|
|
<dl>
|
|
<dt>QEMU version:</dt>
|
|
<dd><? $qemu_info = $lv->get_connect_information(); echo $qemu_info['hypervisor_major'].'.'.$qemu_info['hypervisor_minor'].'.'.$qemu_info['hypervisor_release']; ?></dd>
|
|
</dl>
|
|
|
|
<dl>
|
|
<dt>Libvirt storage location:</dt>
|
|
<dd><?=$domain_cfg['IMAGE_FILE'];?></dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p>This is the libvirt volume.</p>
|
|
</blockquote>
|
|
<?else: /* Libvirt is stopped */ ?>
|
|
<dl>
|
|
<dt>Libvirt vdisk size:</dt>
|
|
<dd><input id="IMAGE_SIZE" type="number" min="1" name="IMAGE_SIZE" value="<?=$domain_cfg['IMAGE_SIZE'];?>" style="width:50px;" required="required" />GB <span id="SIZE_ERROR" class="errortext"></span></dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p>If the system needs to create a new libvirt image file, this is the default size to use specified in GB.</p>
|
|
<p>To resize an existing image file, specify the new size here. Next time the Libvirt service is started the file (and file system) will increased to the new size (but never decreased).</p>
|
|
</blockquote>
|
|
|
|
<div class="advanced" markdown="1">
|
|
<dl>
|
|
<dt>Libvirt storage location:</dt>
|
|
<dd><input id="IMAGE_FILE" type="text" name="IMAGE_FILE" value="<?=$domain_cfg['IMAGE_FILE'];?>" placeholder="e.g. /mnt/user/system/libvirt/libvirt.img" data-pickcloseonfile="true" data-pickfilter="img" data-pickroot="/mnt/" data-pickfolders="true" required="required" /> <span id="IMAGE_ERROR" class="errortext"></span></dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p>You must specify an image file for Libvirt. The system will automatically create this file when the Libvirt service is first started.</p>
|
|
</blockquote>
|
|
<?endif;?>
|
|
|
|
<dl>
|
|
<dt>Default VM storage path:</dt>
|
|
<dd><input type="text" id="domaindir" data-pickfolders="true" data-pickfilter="NO_FILES_FILTER" data-pickroot="<?= (is_dir('/mnt/user/') ? '/mnt/user/' : '/mnt/') ?>" name="DOMAINDIR" value="<?=$domain_cfg['DOMAINDIR']?>" placeholder="Click to Select"></dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p>Specify a user share that contains all your VM subdirectories with vdisks</p>
|
|
</blockquote>
|
|
|
|
<dl>
|
|
<dt>Default ISO storage path:</dt>
|
|
<dd><input type="text" id="mediadir" data-pickfolders="true" data-pickfilter="NO_FILES_FILTER" data-pickroot="<?= (is_dir('/mnt/user/') ? '/mnt/user/' : '/mnt/') ?>" name="MEDIADIR" value="<?=$domain_cfg['MEDIADIR']?>" placeholder="Click to Select"></dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p>Specify a user share that contains all your installation media for operating systems</p>
|
|
</blockquote>
|
|
</div>
|
|
|
|
<dl>
|
|
<dt>Default Windows VirtIO driver ISO <span style="font-weight: normal">(optional)</span>:</dt>
|
|
<dd>
|
|
<select id="winvirtio_select" class="narrow">
|
|
<?
|
|
$iso_dir = $domain_cfg['MEDIADIR'];
|
|
if (empty($iso_dir) || !is_dir($iso_dir)) {
|
|
$iso_dir = '/mnt/user/isos/';
|
|
} else {
|
|
$iso_dir = str_replace('//', '/', $iso_dir.'/');
|
|
}
|
|
|
|
$strManual = '';
|
|
if (!empty($domain_cfg['MEDIADIR']) &&
|
|
!empty($domain_cfg['VIRTIOISO']) &&
|
|
dirname($domain_cfg['VIRTIOISO']) != '.' &&
|
|
strpos($iso_dir, dirname($domain_cfg['VIRTIOISO'])) !== 0) {
|
|
$strManual = 'manual';
|
|
}
|
|
|
|
$strMatch = $strManual;
|
|
foreach ($virtio_isos as $key => $value) {
|
|
if (empty($strMatch) &&
|
|
(basename($domain_cfg['VIRTIOISO']) == $value['name']) &&
|
|
is_file($iso_dir.$value['name'])
|
|
) {
|
|
$strMatch = $value['name'];
|
|
}
|
|
echo mk_option($strMatch, $value['name'], $value['name']);
|
|
}
|
|
|
|
echo mk_option($strManual, 'manual', 'Manual');
|
|
?>
|
|
</select><input type="text" id="winvirtio" name="VIRTIOISO" data-pickfilter="iso" data-pickcloseonfile="true" data-pickroot="<?= (is_dir('/mnt/user/') ? '/mnt/user/' : '/mnt/') ?>" value="<?=$domain_cfg['VIRTIOISO']?>"<?if ($var['fsState'] == "Started"):?> placeholder="Click to Select"><i class="fa fa-download" id="download_button" title="Download Windows VirtIO driver ISO"> <span>Download</span></i><span id="download_status"></span<?endif;?>>
|
|
</dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p>Specify the virtual CD-ROM (ISO) that contains the VirtIO Windows drivers as provided by the Fedora Project. Download the latest ISO from here: <a href="https://fedoraproject.org/wiki/Windows_Virtio_Drivers#Direct_download" target="_blank">https://fedoraproject.org/wiki/Windows_Virtio_Drivers#Direct_download</a></p>
|
|
<p>When installing Windows, you will reach a step where no disk devices will be found. There is an option to browse for drivers on that screen. Click browse and locate the additional CD-ROM in the menu. Inside there will be various folders for the different versions of Windows. Open the folder for the version of Windows you are installing and then select the AMD64 subfolder inside (even if you are on an Intel system, select AMD64). Three drivers will be found. Select them all, click next, and the vDisks you have assigned will appear.</p>
|
|
</blockquote>
|
|
|
|
<div class="advanced">
|
|
<dl>
|
|
<dt>Default network bridge:</dt>
|
|
<dd>
|
|
<select id="bridge" name="BRNAME">
|
|
<?
|
|
foreach ($arrValidBridges as $strBridge) {
|
|
echo mk_option($domain_cfg['BRNAME'], $strBridge, $strBridge);
|
|
}
|
|
?>
|
|
</select>
|
|
</dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p>Enter the name of the network bridge you wish to use for your VMs here, otherwise leave the field blank and libvirt will create a bridge that will utilize NAT (network address translation) and act as a DHCP server to hand out IP addresses to virtual machines directly.</p>
|
|
<p>NOTE: You can also specify an network bridge on a per-VM basis.</p>
|
|
</blockquote>
|
|
|
|
<dl>
|
|
<dt>Enable PCIe ACS Override:</dt>
|
|
<dd>
|
|
<select id="pcie_acs_override" class="narrow">
|
|
<?= mk_option(($boolACSInSyslinux ? '1' : '0'), '0', 'No'); ?>
|
|
<?= mk_option(($boolACSInSyslinux ? '1' : '0'), '1', 'Yes'); ?>
|
|
</select>
|
|
</dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p>Warning: Use of this setting could cause possible data corruption with certain hardware configurations. Please visit the Lime Technology forums for more information.</p>
|
|
<p>A reboot will be required for changes to this setting to take affect.</p>
|
|
</blockquote>
|
|
</div>
|
|
|
|
<dl>
|
|
<dt><?if (file_exists("/var/log/libvirt/libvirtd.log")):?><input type="button" class="advanced" onclick="openWindow('/webGui/scripts/tail_log&arg1=libvirt/libvirtd.log','Log Information',600,900);" value="View libvirt log"/><?endif;?> </dt>
|
|
<dd><input type="button" id="applyBtn" value="Apply"/><input type="button" value="Done" onclick="done()"></dd>
|
|
</dl>
|
|
</form>
|
|
|
|
<?if (file_exists("/var/log/libvirt/libvirtd.log")):?>
|
|
<blockquote class="inline_help">
|
|
<p>View the log for libvirt: <a id="openlog" title="/var/log/libvirt/libvirtd.log" href="#" onclick="openWindow('/webGui/scripts/tail_log&arg1=libvirt/libvirtd.log','Log Information',600,900);">/var/log/libvirt/libvirtd.log</a></p>
|
|
</blockquote>
|
|
<?endif;?>
|
|
|
|
<?if ($libvirt_running == 'yes' && trim(shell_exec('stat -c %T -f /etc/libvirt')) == 'btrfs'):?>
|
|
<div class="advanced">
|
|
<div id="title"><span class="left"><img src="/plugins/dynamix.docker.manager/icons/vcard.png" class="icon">Libvirt volume info</span></div>
|
|
|
|
<dl>
|
|
<dt>btrfs filesystem show:</dt>
|
|
<dd><?="<pre>".shell_exec("btrfs filesystem show /etc/libvirt")."</pre>"?></dd>
|
|
</dl>
|
|
|
|
<form markdown="1" method="POST" action="/update.php" target="progressFrame">
|
|
<?exec("/usr/local/emhttp/webGui/scripts/btrfs_scrub status /etc/libvirt", $scrub_status, $retval);?>
|
|
|
|
<dl>
|
|
<dt>btrfs scrub status:</dt>
|
|
<dd><?="<pre>".implode("\n", $scrub_status)."</pre>"?></dd>
|
|
</dl>
|
|
|
|
<?if ($retval != 0):?>
|
|
<input type="hidden" name="#command" value="/webGui/scripts/btrfs_scrub">
|
|
<input type="hidden" name="#arg[1]" value="start">
|
|
<input type="hidden" name="#arg[2]" value="/etc/libvirt">
|
|
<input type="hidden" name="#arg[3]" value="-r">
|
|
|
|
<dl>
|
|
<dt> </dt>
|
|
<dd><input type="submit" value="Scrub"><label><input type="checkbox" name="#arg[3]" value=""> Correct file system errors</label></dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p><b>Scrub</b> runs the <i>btrfs scrub</i> program to check file system integrity.</p>
|
|
<p>If repair is needed you should check the <i>Correct file system errors</i> and run a second Scrub pass; this will permit <i>btrfs scrub</i> to fix the file system.</p>
|
|
</blockquote>
|
|
|
|
<?else:?>
|
|
<input type="hidden" name="#command" value="/webGui/scripts/btrfs_scrub">
|
|
<input type="hidden" name="#arg[1]" value="cancel">
|
|
<input type="hidden" name="#arg[2]" value="/etc/libvirt">
|
|
|
|
<dl>
|
|
<dt> </dt>
|
|
<dd><input type="button" value="Refresh" onclick="refresh()"><input type="submit" value="Cancel"> <i>Running</i></dd>
|
|
</dl>
|
|
<blockquote class="inline_help">
|
|
<p><b>Cancel</b> will cancel the Scrub operation in progress.</p>
|
|
</blockquote>
|
|
|
|
</form>
|
|
<?endif;?>
|
|
</div>
|
|
<?endif;?>
|
|
|
|
<script src="/webGui/javascript/jquery.filetree.js"></script>
|
|
<script src="/webGui/javascript/jquery.switchbutton.js"></script>
|
|
<script src="/plugins/dynamix.vm.manager/scripts/dynamix.vm.manager.js"></script>
|
|
<script>
|
|
$(function(){
|
|
$("#applyBtn").click(function(){
|
|
if ($('#pcie_acs_override').val() == '1') {
|
|
$.getJSON("/plugins/dynamix.vm.manager/VMajax.php", {action: "acs-override-enable"}, function(data) {
|
|
$("#settingsForm").submit();
|
|
});
|
|
} else {
|
|
$.getJSON("/plugins/dynamix.vm.manager/VMajax.php", {action: "acs-override-disable"}, function(data) {
|
|
$("#settingsForm").submit();
|
|
});
|
|
}
|
|
});
|
|
|
|
$("#mediadir").on("input change", function() {
|
|
$("#winvirtio_select").change();
|
|
});
|
|
|
|
var checkDownloadTimer = null;
|
|
var checkOrInitDownload = function(checkonly) {
|
|
clearTimeout(checkDownloadTimer);
|
|
|
|
var $button = $("#download_button");
|
|
var $form = $button.closest('form');
|
|
|
|
var postdata = {
|
|
action: "virtio-win-iso-download",
|
|
download_version: $('#winvirtio_select').val(),
|
|
download_path: $('#mediadir').val(),
|
|
checkonly: ((typeof checkonly === 'undefined') ? false : !!checkonly) ? 1 : 0
|
|
};
|
|
|
|
$form.find('input,select').prop('disabled', true);
|
|
$button.removeClass('fa-download').addClass('fa-circle-o-notch fa-spin');
|
|
|
|
$.post("/plugins/dynamix.vm.manager/VMajax.php", postdata, function( data ) {
|
|
if (data.error) {
|
|
$("#download_status").html('<span style="color: red">' + data.error + '</span>');
|
|
} else {
|
|
$("#download_status").html(data.status);
|
|
|
|
if (data.pid) {
|
|
checkDownloadTimer = setTimeout(checkOrInitDownload, 1000);
|
|
return;
|
|
}
|
|
|
|
if (data.status == 'Done') {
|
|
$("#winvirtio_select").change();
|
|
}
|
|
}
|
|
|
|
$button.removeClass('fa-circle-o-notch fa-spin').addClass('fa-download');
|
|
$form.find('input,select').prop('disabled', false);
|
|
}, "json");
|
|
};
|
|
|
|
$("#SERVICE").change(function changeService() {
|
|
if ($(this).val()=='enable') {
|
|
$('#arraystopped').fadeIn('slow');
|
|
} else {
|
|
$('#arraystopped').fadeOut('fast');
|
|
}
|
|
});
|
|
if ($("#SERVICE").val()!='enable') $('#arraystopped').hide();
|
|
|
|
$("#download_button").click(function downloadVirtIOVersion() {
|
|
if (!$(this).hasClass('fa-spin')) {
|
|
checkOrInitDownload(false);
|
|
}
|
|
});
|
|
|
|
// Fire events below once upon showing page
|
|
$("#winvirtio_select").change(function changeVirtIOVersion() {
|
|
clearTimeout(checkDownloadTimer);
|
|
|
|
if ($(this).val()=='manual') {
|
|
$("#download_button,#download_status").hide('fast');
|
|
$("#winvirtio").show('fast');
|
|
return;
|
|
}
|
|
|
|
$("#winvirtio").hide('fast');
|
|
|
|
var params = {
|
|
action: "virtio-win-iso-info",
|
|
path: $("#mediadir").val(),
|
|
file: $(this).val()
|
|
};
|
|
|
|
$.get("/plugins/dynamix.vm.manager/VMajax.php", params, function( data ) {
|
|
|
|
if (!data.exists) {
|
|
$("#download_button").show('fast');
|
|
$("#download_status").html('').show('fast');
|
|
if (data.pid) {
|
|
checkOrInitDownload(true);
|
|
}
|
|
} else {
|
|
$("#download_button,#download_status").hide('fast');
|
|
$("#winvirtio").val(data.path);
|
|
}
|
|
|
|
}, "json");
|
|
}).change(); // Fire now too!
|
|
|
|
if ($.cookie('vmsettings_view_mode') == 'advanced') {
|
|
$('.advanced').show();
|
|
$('.basic').hide();
|
|
}
|
|
$('.advancedview').switchButton({
|
|
labels_placement: "left",
|
|
on_label: 'Advanced View',
|
|
off_label: 'Basic View',
|
|
checked: $.cookie('vmsettings_view_mode') == 'advanced'
|
|
});
|
|
$('.advancedview').change(function () {
|
|
$('.advanced').toggle('slow');
|
|
$('.basic').toggle('slow');
|
|
$.cookie('vmsettings_view_mode', $('.advancedview').is(':checked') ? 'advanced' : 'basic', { expires: 3650 });
|
|
});
|
|
|
|
showStatus('pid','libvirt/libvirtd');
|
|
|
|
<?if ($var['fsState'] == "Started"):?>
|
|
$("input[data-pickroot]").fileTreeAttach();
|
|
<?endif;?>
|
|
});
|
|
</script>
|