mirror of
https://github.com/unraid/webgui.git
synced 2026-01-19 08:00:24 -06:00
@@ -25,6 +25,7 @@ $busy = "<i class='fa fa-spin fa-circle-o-notch'></i> Please wait... starting up
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.ui.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
||||
<style>
|
||||
table#docker_containers{text-align:left}
|
||||
.basic{display:block}
|
||||
.advanced{display:none;white-space:nowrap}
|
||||
body{-webkit-overflow-scrolling:touch}
|
||||
@@ -70,7 +71,7 @@ $('.tabs').append("<span id='busy' class='red-text strong' style='display:none;p
|
||||
function resize(bind) {
|
||||
var width = [];
|
||||
var h = $('#docker_list').height();
|
||||
var s = Math.max(window.innerHeight-300,370);
|
||||
var s = Math.max(window.innerHeight-340,330);
|
||||
if (h>s || bind) {
|
||||
$('#docker_list').height(s);
|
||||
$('#docker_containers tbody tr:first-child td').each(function(){width.push($(this).width());});
|
||||
|
||||
@@ -111,7 +111,7 @@ $bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c';
|
||||
.errortext{color:#EF3D47;display:none}
|
||||
.fileTree{background:<?=$bgcolor?>;width:305px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
.basic{display:block}
|
||||
.advanced{display:none;white-space:nowrap}
|
||||
.advanced{display:none}
|
||||
select.mask{min-width:0;margin:0 10px 0 4px}
|
||||
select.net{min-width:0;margin:0 4px 0 2px}
|
||||
select option.hide{display:none}
|
||||
|
||||
@@ -86,24 +86,26 @@ foreach ($containers as $ct) {
|
||||
}
|
||||
echo "<div class='advanced' style='width:160px'>Container ID: $id</div>";
|
||||
if ($ct['BaseImage']) echo "<div class='advanced' style='width:160px;'><i class='fa fa-cubes' style='margin-right:5px'></i>".htmlspecialchars(${ct['BaseImage']})."</div>";
|
||||
echo "<div class='advanced' style='width:160px'>By:";
|
||||
echo "<div class='advanced'>By: ";
|
||||
$registry = $info['registry'];
|
||||
list($author,$version) = explode(':',$ct['Image']);
|
||||
if ($registry) {
|
||||
echo "<a href='".htmlspecialchars($registry)."' target='_blank'>".htmlspecialchars($ct['Image'])."</a>";
|
||||
echo "<a href='".htmlspecialchars($registry)."' target='_blank'>".htmlspecialchars($author)."</a>";
|
||||
} else {
|
||||
echo htmlspecialchars($ct['Image']);
|
||||
echo htmlspecialchars($author);
|
||||
}
|
||||
echo "</div></td><td class='updatecolumn'>";
|
||||
if ($updateStatus=='false') {
|
||||
echo "<a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download'></i> update ready</span></a>";
|
||||
echo "<a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> update ready</span></a>";
|
||||
} elseif ($updateStatus=='true') {
|
||||
echo "<span style='color:#44B012;white-space:nowrap;'><i class='fa fa-check'></i> up-to-date</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download'></i> force update</span></a></div>";
|
||||
echo "<span style='color:#44B012;white-space:nowrap;'><i class='fa fa-check fa-fw'></i> up-to-date</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> force update</span></a></div>";
|
||||
} else {
|
||||
echo "<span style='color:#FF2400;white-space:nowrap;'><i class='fa fa-exclamation-triangle'></i> not available</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download'></i> force update</span></a></div>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> force update</span></a></div>";
|
||||
}
|
||||
echo "</td><td>{$ct['NetworkMode']}</td>";
|
||||
echo "<div class='advanced'><i class='fa fa-info-circle fa-fw'></i> $version</div></td>";
|
||||
echo "<td>{$ct['NetworkMode']}</td>";
|
||||
echo "<td style='white-space:nowrap'><span class='docker_readmore'>".implode('<br>',$ports)."</span></td>";
|
||||
echo "<td style='word-break:break-all'><span class='docker_readmore'>".implode('<br>',$paths)."</span></td>";
|
||||
echo "<td class='advanced'><div class='usage-disk sys load-$id'><span id='cpu-$id' style='width:0'></span></div></td>";
|
||||
|
||||
21
plugins/dynamix.docker.manager/include/DockerUpdate.php
Normal file
21
plugins/dynamix.docker.manager/include/DockerUpdate.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2014-2018, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2018, Bergware International.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
|
||||
$DockerTemplates = new DockerTemplates();
|
||||
$DockerTemplates->downloadTemplates();
|
||||
$DockerTemplates->getAllInfo(true);
|
||||
?>
|
||||
@@ -186,7 +186,7 @@ function resumeAll() {
|
||||
function checkAll() {
|
||||
$('input[type=button]').prop('disabled',true);
|
||||
$('.updatecolumn').html('<span style="color:#267CA8"><i class="fa fa-refresh fa-spin"></i> checking...</span>');
|
||||
loadlist();
|
||||
$.post('/plugins/dynamix.docker.manager/include/DockerUpdate.php',{},function(){loadlist();});
|
||||
}
|
||||
function updateAll() {
|
||||
$('input[type=button]').prop('disabled',true);
|
||||
|
||||
@@ -33,7 +33,7 @@ $check = $notify['version'] ? 0 : 1;
|
||||
function resize(bind) {
|
||||
var width = [];
|
||||
var h = $('#plugin_list').height();
|
||||
var s = Math.max(window.innerHeight-300,370);
|
||||
var s = Math.max(window.innerHeight-340,330);
|
||||
if (h>s || bind) {
|
||||
$('#plugin_list').height(s);
|
||||
$('#plugin_table tbody tr:first-child td').each(function(){width.push($(this).width());});
|
||||
|
||||
@@ -128,7 +128,7 @@ tbody > tr.sortable:hover{cursor:move}
|
||||
function resize(bind) {
|
||||
var width = [];
|
||||
var h = $('#kvm_list').height();
|
||||
var s = Math.max(window.innerHeight-300,370);
|
||||
var s = Math.max(window.innerHeight-340,330);
|
||||
if (h>s || bind) {
|
||||
$('#kvm_list').height(s);
|
||||
$('#kvm_table tbody tr:first-child td').each(function(){width.push($(this).width());});
|
||||
|
||||
@@ -29,33 +29,38 @@ if (empty($strLoadedModules)) {
|
||||
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;
|
||||
}
|
||||
function scan($area, $text) {
|
||||
return strpos($area,$text)!==false;
|
||||
}
|
||||
$bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c';
|
||||
function detect(&$syslinux, $key) {
|
||||
$size = count($syslinux);
|
||||
$menu = $i = 0;
|
||||
$value = '';
|
||||
// find the default section
|
||||
while ($i < $size) {
|
||||
if (scan($syslinux[$i],'label ')) {
|
||||
$n = $i + 1;
|
||||
// find the current requested setting
|
||||
while (!scan($syslinux[$n],'label ') && $n < $size) {
|
||||
if (scan($syslinux[$n],'menu default')) $menu = 1;
|
||||
if (scan($syslinux[$n],'append')) foreach (explode(' ',$syslinux[$n]) as $cmd) if (scan($cmd,$key)) {$value = explode('=',$cmd)[1]; break;}
|
||||
$n++;
|
||||
}
|
||||
if ($menu) break; else $i = $n - 1;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
$syslinux = file('/boot/syslinux/syslinux.cfg',FILE_IGNORE_NEW_LINES+FILE_SKIP_EMPTY_LINES);
|
||||
$arrValidBridges = getNetworkBridges();
|
||||
$pcie_acs_override = detect($syslinux, 'pcie_acs_override');
|
||||
$vfio_allow_unsafe = detect($syslinux, 'allow_unsafe_interrupts');
|
||||
$bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c';
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/plugins/dynamix.vm.manager/styles/dynamix.vm.manager.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.switchbutton.css')?>">
|
||||
|
||||
<style>
|
||||
body{-webkit-overflow-scrolling:touch}
|
||||
.errortext{color:#EF3D47;display:none}
|
||||
@@ -73,10 +78,6 @@ body{-webkit-overflow-scrolling:touch}
|
||||
</style>
|
||||
|
||||
<span class="status vhshift"><input type="checkbox" class="advancedview"></span>
|
||||
<?if ($boolACSEnabled != $boolACSInSyslinux):?>
|
||||
<br><p class="notice">You must reboot for changes to take effect</p>
|
||||
<?endif;?>
|
||||
|
||||
<form markdown="1" id="settingsForm" method="POST" action="/update.php" target="progressFrame">
|
||||
<input type="hidden" name="#file" value="<?=htmlspecialchars($domain_cfgfile)?>">
|
||||
<input type="hidden" name="#command" value="/plugins/dynamix/scripts/emhttpd_update">
|
||||
@@ -194,27 +195,35 @@ VM shutdown time-out:
|
||||
> When shutting down the server, this defines how long to wait in seconds for *graceful* VM shutdown before forcing shutdown to continue.
|
||||
> NOTE: It's recommended to shut down guest VMs from within the VM.
|
||||
|
||||
Enable PCIe ACS Override:
|
||||
PCIe ACS override:
|
||||
: <select id="pcie_acs_override" class="narrow">
|
||||
<?= mk_option(($boolACSInSyslinux ? '1' : '0'), '0', 'No'); ?>
|
||||
<?= mk_option(($boolACSInSyslinux ? '1' : '0'), '1', 'Yes'); ?>
|
||||
<?= mk_option($pcie_acs_override, '', 'Disabled'); ?>
|
||||
<?= mk_option($pcie_acs_override, 'downstream', 'Downstream'); ?>
|
||||
<?= mk_option($pcie_acs_override, 'multifunction', 'Multifunction'); ?>
|
||||
<?= mk_option($pcie_acs_override, 'downstream,multifunction', 'Both'); ?>
|
||||
</select>
|
||||
|
||||
> Warning: Use of this setting could cause possible data corruption with certain hardware configurations. Please visit the Lime Technology forums for more information.
|
||||
> A reboot will be required for changes to this setting to take affect.
|
||||
|
||||
VFIO allow unsafe interrupts:
|
||||
: <select id="vfio_allow_unsafe" class="narrow">
|
||||
<?= mk_option($vfio_allow_unsafe, '', 'No'); ?>
|
||||
<?= mk_option($vfio_allow_unsafe, '1', 'Yes'); ?>
|
||||
</select>
|
||||
|
||||
> Warning: Use of this setting could cause possible data corruption with certain hardware configurations. Please visit the Lime Technology forums for more information.
|
||||
> A reboot will be required for changes to this setting to take affect.
|
||||
|
||||
</div>
|
||||
<?if (file_exists("/var/log/libvirt/libvirtd.log")):?>
|
||||
<input type="button" class="advanced" onclick="openWindow('/webGui/scripts/tail_log&arg1=libvirt/libvirtd.log','Libvirt Log',600,900);" value="View libvirt log"/>
|
||||
<input type="button" onclick="openWindow('/webGui/scripts/tail_log&arg1=libvirt/libvirtd.log','Libvirt Log',600,900);" value="View libvirt log"/>
|
||||
<?else:?>
|
||||
|
||||
<?endif;?>
|
||||
: <input type="button" id="applyBtn" value="Apply" disabled><input type="button" value="Done" onclick="done()">
|
||||
</div>
|
||||
<div class="basic" markdown="1">
|
||||
|
||||
: <input type="button" id="applyBtn" value="Apply" disabled><input type="button" value="Done" onclick="done()">
|
||||
</div>
|
||||
</form>
|
||||
<div class="notice reboot" style="display:none;margin-bottom:24px">System must be rebooted for changes to take effect!</div>
|
||||
|
||||
<?if (file_exists("/var/log/libvirt/libvirtd.log")):?>
|
||||
|
||||
@@ -268,183 +277,156 @@ btrfs scrub status:
|
||||
<script src="<?autov('/plugins/dynamix.vm.manager/javascript/dynamix.vm.manager.js')?>"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
$("#applyBtn").click(function(){
|
||||
if ($("#deleteCheckbox").length && $("#deleteCheckbox").is(":checked")) {
|
||||
$("#removeForm").submit();
|
||||
return;
|
||||
}
|
||||
if ($('#pcie_acs_override').val() == '1') {
|
||||
$.getJSON("/plugins/dynamix.vm.manager/include/VMajax.php", {action: "acs-override-enable"}, function(data) {
|
||||
$("#settingsForm").submit();
|
||||
});
|
||||
} else {
|
||||
$.getJSON("/plugins/dynamix.vm.manager/include/VMajax.php", {action: "acs-override-disable"}, function(data) {
|
||||
$("#settingsForm").submit();
|
||||
});
|
||||
}
|
||||
});
|
||||
$("#applyBtn").click(function(){
|
||||
if ($("#deleteCheckbox").length && $("#deleteCheckbox").is(":checked")) {
|
||||
$("#removeForm").submit();
|
||||
return;
|
||||
}
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", {action:'syslinux',pcie:$('#pcie_acs_override').val(),vfio:$('#vfio_allow_unsafe').val()}, function(data){
|
||||
$("#settingsForm").submit();
|
||||
});
|
||||
});
|
||||
|
||||
$("#mediadir").on("input change", function() {
|
||||
$("#winvirtio_select").change();
|
||||
});
|
||||
$("#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
|
||||
};
|
||||
|
||||
$button.removeClass('fa-download').addClass('fa-circle-o-notch fa-spin');
|
||||
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", postdata, function( data ) {
|
||||
if (postdata.download_version != $('#winvirtio_select').val())
|
||||
return;
|
||||
if (data.error) {
|
||||
$("#download_status").html('<span style="color: red">' + data.error + '</span>');
|
||||
$button.removeClass('fa-circle-o-notch fa-spin').addClass('fa-download');
|
||||
} else {
|
||||
$("#download_status").html(data.status);
|
||||
|
||||
if (data.pid) {
|
||||
checkDownloadTimer = setTimeout(checkOrInitDownload, 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.status == 'Done') {
|
||||
$("#winvirtio_select").change();
|
||||
}
|
||||
}
|
||||
|
||||
}, "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);
|
||||
}
|
||||
});
|
||||
|
||||
$("#remove_button").click(function removeVirtIOVersion() {
|
||||
var postdata = {
|
||||
action: "virtio-win-iso-remove",
|
||||
path: $('#mediadir').val(),
|
||||
file: $('#winvirtio_select').val()
|
||||
};
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", postdata, function( data ) {
|
||||
if (postdata.file != $('#winvirtio_select').val())
|
||||
return;
|
||||
|
||||
if (data.success) {
|
||||
$("#winvirtio_select").change();
|
||||
}
|
||||
}, "json");
|
||||
});
|
||||
|
||||
// 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/include/VMajax.php", params, function( data ) {
|
||||
|
||||
if (!data.exists || data.pid) {
|
||||
$("#remove_button").hide('fast');
|
||||
$("#download_button").removeClass('fa-circle-o-notch fa-spin').addClass('fa-download').show('fast');
|
||||
$("#download_status").html('').show('fast');
|
||||
if (data.pid) {
|
||||
checkOrInitDownload(true);
|
||||
}
|
||||
} else {
|
||||
$("#download_button,#download_status").hide('fast');
|
||||
$("#remove_button").show('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;?>
|
||||
|
||||
if ($("#IMAGE_FILE").length) {
|
||||
$("#IMAGE_FILE").on("input change", function () {
|
||||
$("#IMAGE_ERROR").fadeOut();
|
||||
$("#applyBtn").prop("disabled", false);
|
||||
<? if (file_exists($domain_cfg['IMAGE_FILE'])) { ?>
|
||||
if ($(this).val() != "<?=$domain_cfg['IMAGE_FILE']?>") {
|
||||
$("#deleteCheckbox").prop("disabled", true).attr("checked", false);
|
||||
$("#deletePanel").fadeOut();
|
||||
} else {
|
||||
$("#deleteCheckbox").attr("checked", false).prop("disabled", false);
|
||||
$("#deletePanel").fadeIn();
|
||||
}
|
||||
<? } ?>
|
||||
});
|
||||
|
||||
$("#deleteCheckbox").change(function () {
|
||||
var checked = $(this).is(":checked");
|
||||
$("#SERVICE").prop("disabled", checked).val('disable');
|
||||
$("#IMAGE_SIZE").prop("disabled", checked);
|
||||
$("#IMAGE_FILE").prop("disabled", checked).val("<?=$domain_cfg['IMAGE_FILE']?>");
|
||||
$("#domaindir").prop("disabled", checked);
|
||||
$("#mediadir").prop("disabled", checked);
|
||||
$("#winvirtio_select").prop("disabled", checked);
|
||||
$("#winvirtio").prop("disabled", checked);
|
||||
$("#bridge").prop("disabled", checked);
|
||||
$("#hostshutdown").prop("disabled", checked);
|
||||
$("#pcie_acs_override").prop("disabled", checked);
|
||||
$("#vm_shutdown_timeout").prop("disabled", checked);
|
||||
$("#applyBtn").val(checked ? "Delete" : "Apply").removeAttr('disabled');
|
||||
});
|
||||
}
|
||||
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
|
||||
};
|
||||
$button.removeClass('fa-download').addClass('fa-circle-o-notch fa-spin');
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", postdata, function(data){
|
||||
if (postdata.download_version != $('#winvirtio_select').val())
|
||||
return;
|
||||
if (data.error) {
|
||||
$("#download_status").html('<span style="color: red">' + data.error + '</span>');
|
||||
$button.removeClass('fa-circle-o-notch fa-spin').addClass('fa-download');
|
||||
} else {
|
||||
$("#download_status").html(data.status);
|
||||
if (data.pid) {
|
||||
checkDownloadTimer = setTimeout(checkOrInitDownload, 1000);
|
||||
return;
|
||||
}
|
||||
if (data.status == 'Done') {
|
||||
$("#winvirtio_select").change();
|
||||
}
|
||||
}
|
||||
}, "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);
|
||||
}
|
||||
});
|
||||
$("#remove_button").click(function removeVirtIOVersion() {
|
||||
var postdata = {
|
||||
action: "virtio-win-iso-remove",
|
||||
path: $('#mediadir').val(),
|
||||
file: $('#winvirtio_select').val()
|
||||
};
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", postdata, function(data){
|
||||
if (postdata.file != $('#winvirtio_select').val()) return;
|
||||
if (data.success) {
|
||||
$("#winvirtio_select").change();
|
||||
}
|
||||
}, "json");
|
||||
});
|
||||
// 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()
|
||||
};
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", params, function(data){
|
||||
if (!data.exists || data.pid) {
|
||||
$("#remove_button").hide('fast');
|
||||
$("#download_button").removeClass('fa-circle-o-notch fa-spin').addClass('fa-download').show('fast');
|
||||
$("#download_status").html('').show('fast');
|
||||
if (data.pid) {
|
||||
checkOrInitDownload(true);
|
||||
}
|
||||
} else {
|
||||
$("#download_button,#download_status").hide('fast');
|
||||
$("#remove_button").show('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;?>
|
||||
if ($("#IMAGE_FILE").length) {
|
||||
$("#IMAGE_FILE").on("input change", function(){
|
||||
$("#IMAGE_ERROR").fadeOut();
|
||||
$("#applyBtn").prop("disabled", false);
|
||||
<? if (file_exists($domain_cfg['IMAGE_FILE'])) { ?>
|
||||
if ($(this).val() != "<?=$domain_cfg['IMAGE_FILE']?>") {
|
||||
$("#deleteCheckbox").prop("disabled", true).attr("checked", false);
|
||||
$("#deletePanel").fadeOut();
|
||||
} else {
|
||||
$("#deleteCheckbox").attr("checked", false).prop("disabled", false);
|
||||
$("#deletePanel").fadeIn();
|
||||
}
|
||||
<? } ?>
|
||||
});
|
||||
$("#deleteCheckbox").change(function(){
|
||||
var checked = $(this).is(":checked");
|
||||
$("#SERVICE").prop("disabled", checked).val('disable');
|
||||
$("#IMAGE_SIZE").prop("disabled", checked);
|
||||
$("#IMAGE_FILE").prop("disabled", checked).val("<?=$domain_cfg['IMAGE_FILE']?>");
|
||||
$("#domaindir").prop("disabled", checked);
|
||||
$("#mediadir").prop("disabled", checked);
|
||||
$("#winvirtio_select").prop("disabled", checked);
|
||||
$("#winvirtio").prop("disabled", checked);
|
||||
$("#bridge").prop("disabled", checked);
|
||||
$("#hostshutdown").prop("disabled", checked);
|
||||
$("#pcie_acs_override").prop("disabled", checked);
|
||||
$("#vm_shutdown_timeout").prop("disabled", checked);
|
||||
$("#applyBtn").val(checked ? "Delete" : "Apply").removeAttr('disabled');
|
||||
});
|
||||
}
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", {action:'reboot'}, function(data){
|
||||
if (data.modified) $('div.notice.reboot').show(); else $('div.notice.reboot').hide();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1092,24 +1092,28 @@
|
||||
foreach ($hostnew as $key => $device) {
|
||||
$auto = $device['tag'];
|
||||
$vendor = $device['source']['vendor']['@attributes']['id'];
|
||||
$remove = false;
|
||||
list($product,$remove) = explode('#',$device['source']['product']['@attributes']['id']);
|
||||
$remove_usb = $remove_pci = false;
|
||||
list($product,$remove_usb) = explode('#',$device['source']['product']['@attributes']['id']);
|
||||
$pci = $device['source']['address']['@attributes'];
|
||||
if ($remove) unset($new['devices']['hostdev'][$key]);
|
||||
list($function,$remove_pci) = explode('#',$pci['function']);
|
||||
if ($remove_usb || $remove_pci) unset($new['devices']['hostdev'][$key]);
|
||||
foreach ($hostold as $k => $d) {
|
||||
$v = $d['source']['vendor']['@attributes']['id'];
|
||||
$p = $d['source']['product']['@attributes']['id'];
|
||||
$p2 = $d['source']['address']['@attributes'];
|
||||
if ($v && $p && $v==$vendor && $p==$product) unset($old['devices']['hostdev'][$k]);
|
||||
if ($p2['bus'] && $p2['slot'] && $p2['function'] && $p2['bus']==$pci['bus'] && $p2['slot']==$pci['slot'] && $p2['function']==$pci['function']) unset($old['devices']['hostdev'][$k]);
|
||||
if ($p2['bus'] && $p2['slot'] && $p2['function'] && $p2['bus']==$pci['bus'] && $p2['slot']==$pci['slot'] && $p2['function']==$function) unset($old['devices']['hostdev'][$k]);
|
||||
}
|
||||
}
|
||||
// do not overwrite existing driver type settings
|
||||
$disks = $new['devices']['disk'];
|
||||
foreach ($disks as $key => $disk) unset($new['devices']['disk'][$key]['driver']['@attributes']['type']);
|
||||
// settings not in the GUI, but maybe customized
|
||||
unset($new['memoryBacking'], $new['clock'], $new['features']);
|
||||
// update parent arrays
|
||||
if (!$old['devices']['hostdev']) unset($old['devices']['hostdev']);
|
||||
if (!$new['devices']['hostdev']) unset($new['devices']['hostdev']);
|
||||
unset($old['cputune']['vcpupin']);
|
||||
unset($old['cputune']['vcpupin'],$old['devices']['graphics'],$old['devices']['video']);
|
||||
// set namespace
|
||||
$new['metadata']['vmtemplate']['@attributes']['xmlns'] = 'unraid';
|
||||
}
|
||||
|
||||
@@ -1431,6 +1431,16 @@ $(function() {
|
||||
$button.closest('form').find('input[name="usb[]"],input[name="pci[]"]').each(function(){
|
||||
if (!$(this).prop('checked')) $(this).prop('checked',true).val($(this).val()+'#remove');
|
||||
});
|
||||
// remove unused graphic cards
|
||||
var gpus = [], i = 0;
|
||||
do {
|
||||
var gpu = $button.closest('form').find('select[name="gpu['+(i++)+'][id]"] option:selected').val();
|
||||
if (gpu) gpus.push(gpu);
|
||||
} while (gpu);
|
||||
$button.closest('form').find('select[name="gpu[0][id]"] option').each(function(){
|
||||
var gpu = $(this).val();
|
||||
if (gpu != 'vnc' && !gpus.includes(gpu)) $('form#vmform').append('<input type="hidden" name="pci[]" value="'+gpu+'#remove">');
|
||||
});
|
||||
<?endif?>
|
||||
var postdata = $button.closest('form').find('input,select').serialize().replace(/'/g,"%27");
|
||||
<?if (!$boolNew):?>
|
||||
|
||||
@@ -1124,6 +1124,16 @@ $(function() {
|
||||
$button.closest('form').find('input[name="usb[]"],input[name="pci[]"]').each(function(){
|
||||
if (!$(this).prop('checked')) $(this).prop('checked',true).val($(this).val()+'#remove');
|
||||
});
|
||||
// remove unused graphic cards
|
||||
var gpus = [], i = 0;
|
||||
do {
|
||||
var gpu = $button.closest('form').find('select[name="gpu['+(i++)+'][id]"] option:selected').val();
|
||||
if (gpu) gpus.push(gpu);
|
||||
} while (gpu);
|
||||
$button.closest('form').find('select[name="gpu[0][id]"] option').each(function(){
|
||||
var gpu = $(this).val();
|
||||
if (gpu != 'vnc' && !gpus.includes(gpu)) $('form#vmform').append('<input type="hidden" name="pci[]" value="'+gpu+'#remove">');
|
||||
});
|
||||
<?endif?>
|
||||
var postdata = $button.closest('form').find('input,select').serialize().replace(/'/g,"%27");
|
||||
<?if (!$boolNew):?>
|
||||
|
||||
@@ -1126,6 +1126,16 @@ $(function() {
|
||||
$button.closest('form').find('input[name="usb[]"],input[name="pci[]"]').each(function(){
|
||||
if (!$(this).prop('checked')) $(this).prop('checked',true).val($(this).val()+'#remove');
|
||||
});
|
||||
// remove unused graphic cards
|
||||
var gpus = [], i = 0;
|
||||
do {
|
||||
var gpu = $button.closest('form').find('select[name="gpu['+(i++)+'][id]"] option:selected').val();
|
||||
if (gpu) gpus.push(gpu);
|
||||
} while (gpu);
|
||||
$button.closest('form').find('select[name="gpu[0][id]"] option').each(function(){
|
||||
var gpu = $(this).val();
|
||||
if (gpu != 'vnc' && !gpus.includes(gpu)) $('form#vmform').append('<input type="hidden" name="pci[]" value="'+gpu+'#remove">');
|
||||
});
|
||||
<?endif?>
|
||||
var postdata = $button.closest('form').find('input,select').serialize().replace(/'/g,"%27");
|
||||
<?if (!$boolNew):?>
|
||||
|
||||
34
plugins/dynamix/CPUisol.page
Normal file
34
plugins/dynamix/CPUisol.page
Normal file
@@ -0,0 +1,34 @@
|
||||
Menu="CPUset:3"
|
||||
Title="CPU Isolation"
|
||||
Tag="leaf"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2012-2018, Bergware International.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
?>
|
||||
<form name="is">
|
||||
<input type="hidden" name="names" value="isolcpus">
|
||||
<table class='tablesorter shift' style='width:auto'>
|
||||
<thead><tr><th><i class="fa fa-list"></i> Isolation</th><?create()?></tr></thead>
|
||||
<tbody id="table-is"><?=$spinner?></tbody>
|
||||
</table>
|
||||
<input type="button" value="Apply" onclick="apply(this.form)" disabled><input type="button" value="Done" onclick="done()"><span id="wait-is" class="red-text" style="display:none"><i class="fa fa-spinner fa-spin"></i> Please wait...</span>
|
||||
</form>
|
||||
<?if (!$safemode):?>
|
||||
<div class="notice isol" style="display:none">System must be rebooted for changes to take effect!</div>
|
||||
<?else:?>
|
||||
<div class="notice">CPU isolation is prohibited while system is running in SAFE MODE!</div>
|
||||
<?endif;?>
|
||||
|
||||
> CPU isolation allows the user to specify CPU cores that are to be explicitly reserved for assignment (to VMs or Docker containers).
|
||||
>
|
||||
> This is incredibly important for gaming VMs to run smoothly because even if you manually pin your Docker containers to not overlap with your gaming VM,
|
||||
> the host OS can still utilize those same cores as the guest VM needs for things like returning responses for the webGui, running a parity check, btrfs operations, etc.
|
||||
45
plugins/dynamix/CPUpin.page
Normal file
45
plugins/dynamix/CPUpin.page
Normal file
@@ -0,0 +1,45 @@
|
||||
Menu="CPUset:2"
|
||||
Title="CPU Pinning Docker"
|
||||
Tag="map-marker"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2012-2018, Bergware International.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
?>
|
||||
<?if ($dockerd):?>
|
||||
<form name="ct">
|
||||
<input type="hidden" name="names" id="names-ct" value="">
|
||||
<table class='tablesorter shift' style='width:auto'>
|
||||
<thead><tr><th><i class="fa fa-list"></i> Container</th><?create()?></tr></thead>
|
||||
<tbody id="table-ct"><?=$spinner?></tbody>
|
||||
</table>
|
||||
<input type="button" value="Apply" onclick="apply(this.form)" disabled><input type="button" value="Done" onclick="done()"><span id="wait-ct" class="red-text" style="display:none"><i class="fa fa-spinner fa-spin"></i> Please wait...</span>
|
||||
</form>
|
||||
<?else:?>
|
||||
<div class="notice">No CPU pinning available. Docker service must be started</div>
|
||||
<?endif;?>
|
||||
|
||||
> This page gives a total view of the current CPU pinning assignments for Docker containers.<br>
|
||||
> It also allows to modify these assignments.
|
||||
>
|
||||
> Running containers are **stopped first** and restarted after the modification.<br>
|
||||
> Stopped containers are instantly modified and new assignments become active when the user manually starts the container.
|
||||
>
|
||||
> When ***Apply*** is pressed a scan is performed to find the changes, subsequently containers which have changes are modified in parallel.
|
||||
>
|
||||
> *Important: Please wait until all updates are finished before leaving this page*.
|
||||
>
|
||||
> By default NO cores are selected for a Docker container, which means it uses all available cores.<br>
|
||||
> Do not select **ALL** cores for containers, just select **NO** cores if you want unrestricted core use.
|
||||
>
|
||||
> Do not select cores for containers which are *isolated*.
|
||||
> By design a container will only use a single core (the lowest numbered core) when multiple isolated cores are selected.<br>
|
||||
> Usually this is not what a user wants when selecting multiple cores.
|
||||
@@ -1,192 +1,4 @@
|
||||
Menu="OtherSettings"
|
||||
Title="CPU Pinning"
|
||||
Icon="grid.png"
|
||||
Tag="map-marker"
|
||||
Cond="pgrep('libvirtd')!==false || pgrep('dockerd')!==false"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2012-2018, Bergware International.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$libvirtd = pgrep('libvirtd')!==false;
|
||||
$dockerd = pgrep('dockerd')!==false;
|
||||
|
||||
$cpus = cpu_list();
|
||||
$total = count($cpus);
|
||||
$spinner = "<tr><td colspan='".($total+2)."'><div class='spinner'></div></td></tr>";
|
||||
$cpuset = implode(';',$cpus);
|
||||
|
||||
function create() {
|
||||
// create the table header. Make multiple rows when CPU cores are many ;)
|
||||
global $total,$cpus;
|
||||
$loop = floor(($total-1)/32)+1;
|
||||
$text = [];
|
||||
for ($c = 0; $c < $loop; $c++) {
|
||||
$max = ($c == $loop-1 ? ($total%32?:32) : 32);
|
||||
for ($n = 0; $n < $max; $n++) {
|
||||
unset($cpu1,$cpu2);
|
||||
list($cpu1, $cpu2) = preg_split('/[,-]/',$cpus[$c*32+$n]);
|
||||
$text[$n] .="$cpu1<br>";
|
||||
if ($cpu2) $text[$n] .= "$cpu2<br>";
|
||||
}
|
||||
}
|
||||
$label = implode('<br>',array_fill(0,$loop,'CPU:'.($cpu2 ? '<br>HT:':'')));
|
||||
echo "<th>$label</th>".implode(array_map(function($t){return "<th>$t</th>";},$text));
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
table.tablesorter tr>th+th{text-align:right;vertical-align:top}
|
||||
table.tablesorter tr>td+td+td{vertical-align:top}
|
||||
table.tablesorter tr>th+th+th,table.tablesorter tr>td+td{text-align:center}
|
||||
table.tablesorter th:first-child,table.tablesorter td:first-child{width:180px;text-align:left}
|
||||
input.flat{margin:0}
|
||||
input.lock{margin:0}
|
||||
</style>
|
||||
<script>
|
||||
String.prototype.stripper = function(){return this.replace(/ |\(|\)|\[|\]/g,'');}
|
||||
|
||||
function apply(form) {
|
||||
// disable buttons
|
||||
$(form).find('input[value="Apply"]').prop('disabled',true);
|
||||
$(form).find('input[value="Reset"]').val('Done').prop('onclick',null).off('click').click(function(){done();});
|
||||
$('input[value="Done"]').prop('disabled',true);
|
||||
var wait = 0;
|
||||
var id = $(form).prop('name');
|
||||
var args = {};
|
||||
args['id'] = id;
|
||||
args['names'] = form.names.value;
|
||||
// get the 'checked' cpus
|
||||
$(form).find('input[type=checkbox]').each(function(){
|
||||
if ($(this).prop('checked')) args[$(this).prop('name')] = 'on';
|
||||
});
|
||||
// show the instant wait message
|
||||
$('#wait-'+id).show();
|
||||
// step 1: prepare the update and report back the changes
|
||||
$.post('/webGui/include/UpdateOne.php',args,function(reply){
|
||||
if (reply.error) {
|
||||
swal({type:'error', title:'Assignment error', text:reply.error},function(){
|
||||
$('#wait-'+id).hide();
|
||||
$(form).find('input[value="Done"]').val('Reset').prop('disabled',false).prop('onclick',null).off('click').click(function(){reset($('form[name="'+id+'"]'));});
|
||||
});
|
||||
} else if (reply.success) {
|
||||
var data = reply.success.split(';');
|
||||
wait = data.length;
|
||||
for (var i=0; i < data.length; i++) {
|
||||
var name = data[i];
|
||||
$('#'+id+'-'+name.stripper()).show('slow');
|
||||
// step 2: apply the changes by updating the vm or container
|
||||
$.post('/webGui/include/UpdateTwo.php',{id:id,name:encodeURI(name)},function(reply){
|
||||
if (reply.error) {
|
||||
// report error and reload table
|
||||
swal({type:'error', title:'Execution error', text:reply.error},function(){
|
||||
$('#wait-'+id).hide();
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
reset($('form[name="'+id+'"]'));
|
||||
});
|
||||
} else {
|
||||
$('#'+id+'-'+reply.success.stripper()).hide('slow');
|
||||
// cleanup when all is done
|
||||
if (!--wait) {
|
||||
setTimeout(function(){$('#wait-'+id).hide();},500);
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
$('#wait-'+id).hide();
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
}
|
||||
});
|
||||
}
|
||||
function vm() {
|
||||
// fetch the current vm assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'vm',cpus:'<?=$cpuset?>'},function(d){
|
||||
var data = d.split('\0');
|
||||
$('#table-vm').html(data[0]);
|
||||
$('#names-vm').val(data[1]);
|
||||
buttons(document.vm);
|
||||
});
|
||||
}
|
||||
function ct() {
|
||||
// fetch the current container assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'ct',cpus:'<?=$cpuset?>'},function(d){
|
||||
var data = d.split('\0');
|
||||
$('#table-ct').html(data[0]);
|
||||
$('#names-ct').val(data[1]);
|
||||
buttons(document.ct);
|
||||
});
|
||||
}
|
||||
function reset(form) {
|
||||
// undo changes without a complete refresh of the page
|
||||
$(form).find('input[value="Apply"]').prop('disabled',true);
|
||||
$(form).find('input[value="Reset"]').val('Done').prop('onclick',null).off('click').click(function(){done();});
|
||||
switch ($(form).prop('name')) {
|
||||
case 'vm': $('#table-vm').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); vm(); break;
|
||||
case 'ct': $('#table-ct').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); ct(); break;
|
||||
}
|
||||
}
|
||||
function buttons(form) {
|
||||
$(form).find('input[type=checkbox]').each(function(){$(this).on('change',function(){
|
||||
var checked = 'input[name^="'+$(this).prop('name').split(':')[0]+':'+'"]:checked';
|
||||
var cores = $(form).find(checked).length;
|
||||
// vms must have at least one core selected
|
||||
if ($(form).prop('name')=='vm') $(form).find(checked).prop('disabled',cores<2);
|
||||
// we need the Apply and Done buttons react on checkbox changes
|
||||
$(form).find('input[value="Apply"]').prop('disabled',false);
|
||||
$(form).find('input[value="Done"]').val('Reset').prop('onclick',null).off('click').click(function(){reset(form);});
|
||||
});});
|
||||
}
|
||||
$(function(){
|
||||
<?if ($libvirtd):?>
|
||||
vm();
|
||||
<?endif;?>
|
||||
<?if ($dockerd):?>
|
||||
ct();
|
||||
<?endif;?>
|
||||
});
|
||||
</script>
|
||||
|
||||
> This page gives a total view of the current CPU pinning assignments for both VMs and Docker containers.<br>
|
||||
> It also allows to modify these assignments.
|
||||
>
|
||||
> Running VMs or containers are **stopped first** and restarted after the modification.<br>
|
||||
> Stopped VMs or containers are instantly modified and new assignments become active when the user manually starts the VM or container.
|
||||
>
|
||||
> When ***Apply*** is pressed a scan is performed to find the changes, subsequently only VMs or containers which have changes are modified in parallel.
|
||||
>
|
||||
> *Please wait until all updates are finished*.
|
||||
>
|
||||
> By default NO cores are selected for a Docker container, which means it uses all available cores.<br>
|
||||
> **Do not select ALL cores, just select NONE**
|
||||
|
||||
<?if ($libvirtd):?>
|
||||
<form name="vm">
|
||||
<input type="hidden" name="names" id="names-vm" value="">
|
||||
<table class='tablesorter shift' style='width:auto'>
|
||||
<thead><tr><th><i class="fa fa-list"></i> VM</th><?create()?></tr></thead>
|
||||
<tbody id="table-vm"><?=$spinner?></tbody>
|
||||
</table>
|
||||
<input type="button" value="Apply" onclick="apply(this.form)" disabled><input type="button" value="Done" onclick="done()"><span id="wait-vm" class="red-text" style="display:none"><i class="fa fa-spinner fa-spin"></i> Please wait...</span>
|
||||
</form>
|
||||
<br>
|
||||
<?endif;?>
|
||||
<?if ($dockerd):?>
|
||||
<form name="ct">
|
||||
<input type="hidden" name="names" id="names-ct" value="">
|
||||
<table class='tablesorter <?=$libvirtd?'':'shift'?>' style='width:auto'>
|
||||
<thead><tr><th><i class="fa fa-list"></i> Container</th><?create()?></tr></thead>
|
||||
<tbody id="table-ct"><?=$spinner?></tbody>
|
||||
</table>
|
||||
<input type="button" value="Apply" onclick="apply(this.form)" disabled><input type="button" value="Done" onclick="done()"><span id="wait-ct" class="red-text" style="display:none"><i class="fa fa-spinner fa-spin"></i> Please wait...</span>
|
||||
</form>
|
||||
<?endif;?>
|
||||
Type="xmenu"
|
||||
Icon="grid.png"
|
||||
202
plugins/dynamix/CPUvms.page
Normal file
202
plugins/dynamix/CPUvms.page
Normal file
@@ -0,0 +1,202 @@
|
||||
Menu="CPUset:1"
|
||||
Title="CPU Pinning VM"
|
||||
Tag="map-marker"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2012-2018, Bergware International.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$libvirtd = pgrep('libvirtd')!==false;
|
||||
$dockerd = pgrep('dockerd')!==false;
|
||||
|
||||
$cpus = cpu_list();
|
||||
$total = count($cpus);
|
||||
$spinner = "<tr><td colspan='".($total+2)."'><div class='spinner'></div></td></tr>";
|
||||
$cpuset = implode(';',$cpus);
|
||||
|
||||
function create() {
|
||||
// create the table header. Make multiple rows when CPU cores are many ;)
|
||||
global $total,$cpus;
|
||||
$loop = floor(($total-1)/32)+1;
|
||||
$text = [];
|
||||
for ($c = 0; $c < $loop; $c++) {
|
||||
$max = ($c==$loop-1 ? ($total%32?:32) : 32);
|
||||
for ($n = 0; $n < $max; $n++) {
|
||||
unset($cpu1,$cpu2);
|
||||
list($cpu1, $cpu2) = preg_split('/[,-]/',$cpus[$c*32+$n]);
|
||||
$text[$n] .="$cpu1<br>";
|
||||
if ($cpu2) $text[$n] .= "$cpu2<br>";
|
||||
}
|
||||
}
|
||||
$label = implode('<br>',array_fill(0,$loop,'CPU:'.($cpu2 ? '<br>HT:':'')));
|
||||
echo "<th>$label</th>".implode(array_map(function($t){return "<th>$t</th>";},$text));
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
table.tablesorter tr>th+th{text-align:right;vertical-align:top}
|
||||
table.tablesorter tr>td+td+td{vertical-align:top}
|
||||
table.tablesorter tr>th+th+th,table.tablesorter tr>td+td{text-align:center}
|
||||
table.tablesorter th:first-child,table.tablesorter td:first-child{width:180px;text-align:left}
|
||||
input.flat{margin:0}
|
||||
input.lock{margin:0}
|
||||
</style>
|
||||
<script>
|
||||
String.prototype.stripper = function(){return this.replace(/ |\(|\)|\[|\]/g,'');}
|
||||
|
||||
function apply(form) {
|
||||
// disable buttons
|
||||
$(form).find('input[value="Apply"]').prop('disabled',true);
|
||||
$(form).find('input[value="Reset"]').val('Done').prop('onclick',null).off('click').click(function(){done();});
|
||||
$('input[value="Done"]').prop('disabled',true);
|
||||
var wait = 0;
|
||||
var id = $(form).prop('name');
|
||||
var args = {};
|
||||
args['id'] = id;
|
||||
args['names'] = form.names.value;
|
||||
// get the 'checked' cpus
|
||||
$(form).find('input[type=checkbox]').each(function(){
|
||||
if ($(this).prop('checked')) args[$(this).prop('name')] = 'on';
|
||||
});
|
||||
// show the instant wait message
|
||||
$('#wait-'+id).show();
|
||||
// step 1: prepare the update and report back the changes
|
||||
$.post('/webGui/include/UpdateOne.php',args,function(reply){
|
||||
if (reply.error) {
|
||||
swal({type:'error', title:'Assignment error', text:reply.error},function(){
|
||||
$('#wait-'+id).hide();
|
||||
$(form).find('input[value="Done"]').val('Reset').prop('disabled',false).prop('onclick',null).off('click').click(function(){reset($('form[name="'+id+'"]'));});
|
||||
});
|
||||
} else if (reply.success) {
|
||||
var data = reply.success.split(';');
|
||||
wait = data.length;
|
||||
for (var i=0; i < data.length; i++) {
|
||||
var name = data[i];
|
||||
$('#'+id+'-'+name.stripper()).show('slow');
|
||||
// step 2: apply the changes by updating the vm or container
|
||||
$.post('/webGui/include/UpdateTwo.php',{id:id,name:encodeURI(name)},function(reply){
|
||||
if (reply.error) {
|
||||
// report error and reload table
|
||||
swal({type:'error', title:'Execution error', text:reply.error},function(){
|
||||
$('#wait-'+id).hide();
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
reset($('form[name="'+id+'"]'));
|
||||
});
|
||||
} else {
|
||||
$('#'+id+'-'+reply.success.stripper()).hide('slow');
|
||||
// cleanup when all is done
|
||||
if (!--wait) {
|
||||
setTimeout(function(){$('#wait-'+id).hide();},500);
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
// isolated cpus, need reboot notice?
|
||||
if (id == 'is') notice();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
$('#wait-'+id).hide();
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
if (id == 'is') notice();
|
||||
}
|
||||
});
|
||||
}
|
||||
function vm() {
|
||||
// fetch the current vm assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'vm',cpus:'<?=$cpuset?>'},function(d){
|
||||
var data = d.split('\0');
|
||||
$('#table-vm').html(data[0]);
|
||||
$('#names-vm').val(data[1]);
|
||||
buttons(document.vm);
|
||||
});
|
||||
}
|
||||
function ct() {
|
||||
// fetch the current container assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'ct',cpus:'<?=$cpuset?>'},function(d){
|
||||
var data = d.split('\0');
|
||||
$('#table-ct').html(data[0]);
|
||||
$('#names-ct').val(data[1]);
|
||||
buttons(document.ct);
|
||||
});
|
||||
}
|
||||
function is() {
|
||||
// fetch the current isolcpu assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'is',cpus:'<?=$cpuset?>'},function(d){
|
||||
$('#table-is').html(d);
|
||||
buttons(document.is);
|
||||
<?if ($safemode):?>
|
||||
$('#table-is').find('input[type=checkbox]').prop('disabled',true);
|
||||
<?endif;?>
|
||||
});
|
||||
}
|
||||
function notice() {
|
||||
// notice to reboot system after changes
|
||||
$.post('/webGui/include/CPUset.php',{id:'cmd'},function(d){
|
||||
if (d==1) $('div.notice.isol').show(); else $('div.notice.isol').hide();
|
||||
});
|
||||
}
|
||||
function reset(form) {
|
||||
// undo changes without a complete refresh of the page
|
||||
$(form).find('input[value="Apply"]').prop('disabled',true);
|
||||
$(form).find('input[value="Reset"]').val('Done').prop('onclick',null).off('click').click(function(){done();});
|
||||
switch ($(form).prop('name')) {
|
||||
case 'vm': $('#table-vm').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); vm(); break;
|
||||
case 'ct': $('#table-ct').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); ct(); break;
|
||||
case 'is': $('#table-is').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); is(); break;
|
||||
}
|
||||
}
|
||||
function buttons(form) {
|
||||
$(form).find('input[type=checkbox]').each(function(){$(this).on('change',function(){
|
||||
var total = $(form).find('input[type=checkbox]').length;
|
||||
var checked = 'input[name^="'+$(this).prop('name').split(':')[0]+':'+'"]:checked';
|
||||
var cores = $(form).find(checked).length;
|
||||
// vms must have at least one core selected
|
||||
if ($(form).prop('name')=='vm') $(form).find(checked).prop('disabled',cores<2);
|
||||
// isolation may not have all cores selected
|
||||
if ($(form).prop('name')=='is' && $(this).prop('checked')) $(this).prop('checked',cores<total);
|
||||
// we need the Apply and Done buttons react on checkbox changes
|
||||
$(form).find('input[value="Apply"]').prop('disabled',false);
|
||||
$(form).find('input[value="Done"]').val('Reset').prop('onclick',null).off('click').click(function(){reset(form);});
|
||||
});});
|
||||
}
|
||||
$(function(){
|
||||
<?if ($libvirtd):?>
|
||||
vm();
|
||||
<?endif;?>
|
||||
<?if ($dockerd):?>
|
||||
ct();
|
||||
<?endif;?>
|
||||
is();
|
||||
notice();
|
||||
});
|
||||
</script>
|
||||
<?if ($libvirtd):?>
|
||||
<form name="vm">
|
||||
<input type="hidden" name="names" id="names-vm" value="">
|
||||
<table class='tablesorter shift' style='width:auto'>
|
||||
<thead><tr><th><i class="fa fa-list"></i> VM</th><?create()?></tr></thead>
|
||||
<tbody id="table-vm"><?=$spinner?></tbody>
|
||||
</table>
|
||||
<input type="button" value="Apply" onclick="apply(this.form)" disabled><input type="button" value="Done" onclick="done()"><span id="wait-vm" class="red-text" style="display:none"><i class="fa fa-spinner fa-spin"></i> Please wait...</span>
|
||||
</form>
|
||||
<?else:?>
|
||||
<div class="notice">No CPU pinning available. VM service must be started</div>
|
||||
<?endif;?>
|
||||
|
||||
> This page gives a total view of the current CPU pinning assignments for VMs.<br>
|
||||
> It also allows to modify these assignments.
|
||||
>
|
||||
> Running VMs are **stopped first** and restarted after the modification.<br>
|
||||
> Stopped VMs are instantly modified and new assignments become active when the user manually starts the VM.
|
||||
>
|
||||
> When ***Apply*** is pressed a scan is performed to find the changes, subsequently only VMs which have changes are modified in parallel.
|
||||
>
|
||||
> *Important: Please wait until all updates are finished before leaving this page*.
|
||||
@@ -32,7 +32,7 @@ Array.prototype.remove = function() {
|
||||
function resize(bind) {
|
||||
var width = [];
|
||||
var h = $('#archive_list').height();
|
||||
var s = Math.max(window.innerHeight-300,370);
|
||||
var s = Math.max(window.innerHeight-340,330);
|
||||
if (h>s || bind) {
|
||||
$('#archive_list').height(s);
|
||||
$('#archive_table tbody tr:first-child td').each(function(){width.push($(this).width());});
|
||||
|
||||
@@ -17,7 +17,7 @@ Tag="list"
|
||||
<?if ($display['resize']):?>
|
||||
<script>
|
||||
function resize() {
|
||||
$('div.up').height(Math.max(window.innerHeight-280,370)).show();
|
||||
$('div.up').height(Math.max(window.innerHeight-320,330)).show();
|
||||
}
|
||||
$(function() {
|
||||
resize();
|
||||
|
||||
@@ -17,7 +17,7 @@ Tag="list"
|
||||
<?if ($display['resize']):?>
|
||||
<script>
|
||||
function resize() {
|
||||
$('pre.up').height(Math.max(window.innerHeight-280,370)).show();
|
||||
$('pre.up').height(Math.max(window.innerHeight-320,330)).show();
|
||||
}
|
||||
$(function() {
|
||||
resize();
|
||||
|
||||
@@ -56,7 +56,7 @@ function toggle(checked) {
|
||||
}
|
||||
<?if ($display['resize']):?>
|
||||
function resize() {
|
||||
$('pre.up').height(Math.max(window.innerHeight-280,370)).show();
|
||||
$('pre.up').height(Math.max(window.innerHeight-320,330)).show();
|
||||
}
|
||||
$(function() {
|
||||
resize();
|
||||
|
||||
@@ -17,7 +17,7 @@ Tag="list"
|
||||
<?if ($display['resize']):?>
|
||||
<script>
|
||||
function resize() {
|
||||
$('pre.up').height(Math.max(window.innerHeight-280,370)).show();
|
||||
$('pre.up').height(Math.max(window.innerHeight-320,330)).show();
|
||||
}
|
||||
$(function() {
|
||||
resize();
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$cpus = explode(';',$_POST['cpus']);
|
||||
|
||||
function scan($area, $text) {
|
||||
return strpos($area,$text)!==false;
|
||||
}
|
||||
|
||||
function create($id, $name, $vcpu) {
|
||||
// create the list of checkboxes. Make multiple rows when CPU cores are many ;)
|
||||
global $cpus;
|
||||
@@ -83,5 +87,62 @@ case 'ct':
|
||||
// return the cpu assignments and available container names
|
||||
echo "\0".implode(';',array_map('urlencode',$cts));
|
||||
break;
|
||||
case 'is':
|
||||
$syslinux = file('/boot/syslinux/syslinux.cfg',FILE_IGNORE_NEW_LINES+FILE_SKIP_EMPTY_LINES);
|
||||
$size = count($syslinux);
|
||||
$menu = $i = 0;
|
||||
$isolcpus = $isol = [];
|
||||
// find the default section
|
||||
while ($i < $size) {
|
||||
if (scan($syslinux[$i],'label ')) {
|
||||
$n = $i + 1;
|
||||
// find the current isolcpus setting
|
||||
while (!scan($syslinux[$n],'label ') && $n < $size) {
|
||||
if (scan($syslinux[$n],'menu default')) $menu = 1;
|
||||
if (scan($syslinux[$n],'append')) foreach (explode(' ',$syslinux[$n]) as $cmd) if (scan($cmd,'isolcpus')) {$isol = explode('=',$cmd)[1]; break;}
|
||||
$n++;
|
||||
}
|
||||
if ($menu) break; else $i = $n - 1;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if ($isol != '') {
|
||||
// convert to individual numbers
|
||||
foreach (explode(',',$isol) as $cpu) {
|
||||
unset($first,$last);
|
||||
list($first,$last) = explode('-',$cpu);
|
||||
$last = $last ?: $first;
|
||||
for ($x = $first; $x <= $last; $x++) $isolcpus[] = $x;
|
||||
}
|
||||
sort($isolcpus,SORT_NUMERIC);
|
||||
$isolcpus = array_unique($isolcpus,SORT_NUMERIC);
|
||||
}
|
||||
echo "<tr><td>Isolated CPUs</td>";
|
||||
create('is', 'isolcpus', $isolcpus);
|
||||
echo "</tr>";
|
||||
break;
|
||||
case 'cmd':
|
||||
$isolcpus_now = $isolcpus_new = '';
|
||||
$syslinux = file('/boot/syslinux/syslinux.cfg',FILE_IGNORE_NEW_LINES+FILE_SKIP_EMPTY_LINES);
|
||||
$cmdline = explode(' ',file_get_contents('/proc/cmdline'));
|
||||
foreach ($cmdline as $cmd) if (scan($cmd,'isolcpus')) {$isolcpus_now = $cmd; break;}
|
||||
$size = count($syslinux);
|
||||
$menu = $i = 0;
|
||||
// find the default section
|
||||
while ($i < $size) {
|
||||
if (scan($syslinux[$i],'label ')) {
|
||||
$n = $i + 1;
|
||||
// find the current isolcpus setting
|
||||
while (!scan($syslinux[$n],'label ') && $n < $size) {
|
||||
if (scan($syslinux[$n],'menu default')) $menu = 1;
|
||||
if (scan($syslinux[$n],'append')) foreach (explode(' ',$syslinux[$n]) as $cmd) if (scan($cmd,'isolcpus')) {$isolcpus_new = $cmd; break;}
|
||||
$n++;
|
||||
}
|
||||
if ($menu) break; else $i = $n - 1;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
echo $isolcpus_now==$isolcpus_new ? 0 : 1;
|
||||
break;
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -130,7 +130,7 @@ class custom {
|
||||
// store as single or multi array
|
||||
if (!isset($tags[$node])) {
|
||||
// specific for Unraid
|
||||
if (in_array($node,['hostdev','controller'])) $tags[$node][] = $data; else $tags[$node] = $data;
|
||||
if (in_array($node,['hostdev','controller','disk'])) $tags[$node][] = $data; else $tags[$node] = $data;
|
||||
} elseif (is_array($tags[$node]) && array_keys($tags[$node])===range(0, count($tags[$node])-1)) {
|
||||
$tags[$node][] = $data;
|
||||
} else {
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
.upgrade_notice i{margin:14px;float:right;cursor:pointer}
|
||||
.back_to_top{display:none;position:fixed;bottom:30px;right:12px;color:#e22828;font-size:25px}
|
||||
<?
|
||||
$safemode = strpos(file_get_contents('/proc/cmdline'),'unraidsafemode')!==false;
|
||||
$tasks = find_pages('Tasks');
|
||||
$buttons = find_pages('Buttons');
|
||||
$banner = '/boot/config/plugins/dynamix/banner.png';
|
||||
@@ -524,7 +525,7 @@ $(function() {
|
||||
var top = ($.cookie('top')||0) - $('.tabs').offset().top - 75;
|
||||
if (top>0) {$('html,body').scrollTop(top);}
|
||||
$.removeCookie('top',{path:'/'});
|
||||
<?if (strpos(file_get_contents('/proc/cmdline'),'unraidsafemode')!==false):?>
|
||||
<?if ($safemode):?>
|
||||
showNotice('System running in <b>safe</b> mode');
|
||||
<?else:?>
|
||||
<?$readme = @file_get_contents("$docroot/plugins/unRAIDServer/README.md",false,null,0,20);?>
|
||||
|
||||
@@ -20,7 +20,7 @@ foreach($_POST as $key => $val) {
|
||||
list($name,$cpu) = explode(':',$key);
|
||||
$map[urldecode($name)] .= "$cpu,";
|
||||
}
|
||||
// map holds the list of each vm or container and its newly proposed cpu assignments
|
||||
// map holds the list of each vm, container or isolcpus and its newly proposed cpu assignments
|
||||
$map = array_map(function($d){return substr($d,0,-1);},$map);
|
||||
|
||||
switch ($_POST['id']) {
|
||||
@@ -72,6 +72,14 @@ case 'ct':
|
||||
}
|
||||
$reply = ['success' => (count($changes) ? implode(';',$changes) : '')];
|
||||
break;
|
||||
case 'is':
|
||||
// report changed isolcpus in temporary file
|
||||
foreach ($map as $name => $isolcpu) {
|
||||
file_put_contents("/var/tmp/$name.tmp",$isolcpu);
|
||||
$changes[] = $name;
|
||||
}
|
||||
$reply = ['success' => (count($changes) ? implode(';',$changes) : '')];
|
||||
break;
|
||||
}
|
||||
// signal changes
|
||||
header('Content-Type: application/json');
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
function scan($area, $text) {
|
||||
return strpos($area,$text)!==false;
|
||||
}
|
||||
|
||||
$name = urldecode($_POST['name']);
|
||||
switch ($_POST['id']) {
|
||||
case 'vm':
|
||||
@@ -114,6 +118,58 @@ case 'ct':
|
||||
}
|
||||
$reply = ['success' => $name];
|
||||
break;
|
||||
case 'is':
|
||||
$cfg = '/boot/syslinux/syslinux.cfg';
|
||||
$syslinux = file($cfg, FILE_IGNORE_NEW_LINES+FILE_SKIP_EMPTY_LINES);
|
||||
$size = count($syslinux);
|
||||
$menu = $i = 0;
|
||||
$cmd = [];
|
||||
// find the default section
|
||||
while ($i < $size) {
|
||||
if (scan($syslinux[$i],'label ')) {
|
||||
$n = $i + 1;
|
||||
while (!scan($syslinux[$n],'label ') && $n < $size) {
|
||||
if (scan($syslinux[$n],'menu default')) $menu = 1;
|
||||
// find the current command
|
||||
if (scan($syslinux[$n],'append')) {$cmd = preg_split('/\s+/',trim($syslinux[$n])); break;}
|
||||
$n++;
|
||||
}
|
||||
if ($menu) break; else $i = $n - 1;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if ($cmd) {
|
||||
// modify the current command
|
||||
$file = "/var/tmp/$name.tmp";
|
||||
// read new isolcpus assignments
|
||||
$isolcpus = file_get_contents($file); unlink($file);
|
||||
if ($isolcpus != '') {
|
||||
$numbers = explode(',',$isolcpus);
|
||||
sort($numbers,SORT_NUMERIC);
|
||||
$isolcpus = $previous = array_shift($numbers);
|
||||
$range = false;
|
||||
// convert sequential numbers to a range
|
||||
foreach ($numbers as $number) {
|
||||
if ($number == $previous+1) {
|
||||
$range = true;
|
||||
} else {
|
||||
if ($range) {$isolcpus .= '-'.$previous; $range = false;}
|
||||
$isolcpus .= ','.$number;
|
||||
}
|
||||
$previous = $number;
|
||||
}
|
||||
if ($range) $isolcpus .= '-'.$previous;
|
||||
$isolcpus = "isolcpus=$isolcpus";
|
||||
}
|
||||
// replace an existing setting
|
||||
for ($c = 0; $c < count($cmd); $c++) if (scan($cmd[$c],'isolcpus')) {$cmd[$c] = $isolcpus; break;}
|
||||
// or insert a new setting
|
||||
if ($c == count($cmd) && $isolcpus) array_splice($cmd,-1,0,$isolcpus);
|
||||
$syslinux[$n] = ' '.str_replace(' ',' ',implode(' ',$cmd));
|
||||
file_put_contents($cfg, implode("\n",$syslinux)."\n");
|
||||
}
|
||||
$reply = ['success' => $name];
|
||||
break;
|
||||
}
|
||||
header('Content-Type: application/json');
|
||||
die(json_encode($reply));
|
||||
|
||||
@@ -21,7 +21,7 @@ i.icon{margin-right:4px}
|
||||
i.title{margin-right:8px}
|
||||
hr{border:none;height:1px!important;color:#2b2b2b;background-color:#2b2b2b}
|
||||
input[type=text],input[type=password],input[type=number],input[type=url],input[type=email],input[type=date],input[type=file],textarea,.textarea{font-family:clear-sans;font-size:14px;background:transparent;border:1px solid #e5e5e5;padding:5px 10px;min-height:20px;line-height:20px;outline:none;width:304px;margin:0 20px 0 0;box-shadow:none;color:#f2f2f2}
|
||||
input[type=button],input[type=reset],input[type=submit],button,button[type=button],a.button{font-family:clear-sans;font-size:13px;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:10px 28px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:.125rem;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
input[type=button],input[type=reset],input[type=submit],button,button[type=button],a.button{font-family:clear-sans;font-size:13px;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:10px 20px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:.125rem;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
input[type=checkbox]{vertical-align:middle;margin-right:6px}
|
||||
input[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{-webkit-appearance: none}
|
||||
input[type=number]{-moz-appearance:textfield}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
html{font-family:clear-sans;height:100%}
|
||||
body{font-size:14px;color:#1c1c1c;background:#f2f2f2;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
|
||||
input[type=text],input[type=password],input[type=number],input[type=url],input[type=email],input[type=date],input[type=file],textarea,.textarea{font-family:clear-sans;font-size:14px;background:transparent;border:1px solid #1c1c1c;padding:5px 10px;min-height:20px;line-height:20px;outline:none;width:304px;margin:0 20px 0 0;box-shadow:none;color:#1c1c1c}
|
||||
input[type=button],input[type=reset],input[type=submit],button,button[type=button],a.button{font-family:clear-sans;font-size:13px;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:0 12px 0 0;padding:10px 28px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:.125rem;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
input[type=button],input[type=reset],input[type=submit],button,button[type=button],a.button{font-family:clear-sans;font-size:13px;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:0 12px 0 0;padding:10px 20px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:.125rem;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
input:hover[type=button],input:hover[type=reset],input:hover[type=submit],button:hover,button:hover[type=button],a.button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled],button[disabled],button[type=button][disabled],a.button[disabled]
|
||||
input:hover[type=button][disabled],input:hover[type=reset][disabled],input:hover[type=submit][disabled],button:hover[disabled],button:hover[type=button][disabled],a.button:hover[disabled]
|
||||
|
||||
@@ -21,7 +21,7 @@ i.icon{margin-right:4px}
|
||||
i.title{margin-right:8px}
|
||||
hr{border:none;height:1px!important;color:#e3e3e3;background-color:#e3e3e3}
|
||||
input[type=text],input[type=password],input[type=number],input[type=url],input[type=email],input[type=date],input[type=file],textarea,.textarea{font-family:clear-sans;font-size:14px;background:transparent;border:1px solid #1c1c1c;padding:5px 10px;min-height:20px;line-height:20px;outline:none;width:304px;margin:0 20px 0 0;box-shadow:none;color:#1c1c1c}
|
||||
input[type=button],input[type=reset],input[type=submit],button,button[type=button],a.button{font-family:clear-sans;font-size:13px;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:10px 28px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:.125rem;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
input[type=button],input[type=reset],input[type=submit],button,button[type=button],a.button{font-family:clear-sans;font-size:13px;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:10px 20px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:.125rem;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
input[type=checkbox]{vertical-align:middle;margin-right:6px}
|
||||
input[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{-webkit-appearance: none}
|
||||
input[type=number]{-moz-appearance:textfield}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
body>div.jGrowl{position:fixed}
|
||||
div.jGrowl{font-size:14px}
|
||||
div.jGrowl.top-left{left:70px;top:110px}
|
||||
div.jGrowl.top-right{right:10px;top:110px}
|
||||
div.jGrowl.bottom-left{left:70px;bottom:24px}
|
||||
div.jGrowl.top-left{left:10px;top:100px}
|
||||
div.jGrowl.top-right{right:10px;top:100px}
|
||||
div.jGrowl.bottom-left{left:10px;bottom:24px}
|
||||
div.jGrowl.bottom-right{right:10px;bottom:24px}
|
||||
div.jGrowl.center{top:110px;left:40%}
|
||||
div.jGrowl.center{top:100px;left:40%}
|
||||
div.jGrowl div.jGrowl-notify.alert{color:#F0000C;background-color:#FF9E9E;opacity:0.96;border:1px solid #F0000C;box-shadow:2px 2px 1px #888888}
|
||||
div.jGrowl div.jGrowl-notify.warning{color:#E68A00;background-color:#FEEFB3;opacity:0.96;border:1px solid #E68A00;box-shadow:2px 2px 1px #888888}
|
||||
div.jGrowl div.jGrowl-notify.normal{color:#4F8A10;background-color:#DFF2BF;opacity:0.96;border:1px solid #4F8A10;box-shadow:2px 2px 1px #888888}
|
||||
@@ -13,7 +13,7 @@ div.jGrowl div.jGrowl-notify{min-height:40px;width:380px;padding:10px;margin:5px
|
||||
div.jGrowl div.jGrowl-notify div.jGrowl-header{font-weight:bold}
|
||||
div.jGrowl div.jGrowl-notify div.jGrowl-close{float:right;cursor:pointer}
|
||||
div.jGrowl div.jGrowl-closer{width:400px;color:#808080;background-color:#121510;opacity:0.96;border:2px solid #B0B0B0;margin:5px 0;padding:4px 0;cursor:pointer;font-weight:bold;text-align:center;border-radius:6px}
|
||||
div.jGrowl div.jGrowl-closer.top{position:fixed;top:140px}
|
||||
div.jGrowl div.jGrowl-closer.top{position:fixed;top:130px}
|
||||
@media print{div.jGrowl{display:none}}
|
||||
.ui-dropdownchecklist{background:transparent;border:none;box-shadow:0 1px 0 #f2f2f2;outline:none;height:32px;line-height:32px;cursor:pointer}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #f2f2f2;display:inline-block;cursor:pointer;padding:1px 9px 1px 11px}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
body>div.jGrowl{position:fixed}
|
||||
div.jGrowl{font-size:14px}
|
||||
div.jGrowl.top-left{left:70px;top:110px}
|
||||
div.jGrowl.top-right{right:10px;top:110px}
|
||||
div.jGrowl.bottom-left{left:70px;bottom:24px}
|
||||
div.jGrowl.top-left{left:10px;top:100px}
|
||||
div.jGrowl.top-right{right:10px;top:100px}
|
||||
div.jGrowl.bottom-left{left:10px;bottom:24px}
|
||||
div.jGrowl.bottom-right{right:10px;bottom:24px}
|
||||
div.jGrowl.center{top:110px;left:40%}
|
||||
div.jGrowl.center{top:100px;left:40%}
|
||||
div.jGrowl div.jGrowl-notify.alert{color:#F0000C;background-color:#FF9E9E;opacity:0.96;border:1px solid #F0000C;box-shadow:2px 2px 1px #888888}
|
||||
div.jGrowl div.jGrowl-notify.warning{color:#E68A00;background-color:#FEEFB3;opacity:0.96;border:1px solid #E68A00;box-shadow:2px 2px 1px #888888}
|
||||
div.jGrowl div.jGrowl-notify.normal{color:#4F8A10;background-color:#DFF2BF;opacity:0.96;border:1px solid #4F8A10;box-shadow:2px 2px 1px #888888}
|
||||
@@ -13,7 +13,7 @@ div.jGrowl div.jGrowl-notify{min-height:40px;width:380px;padding:10px;margin:5px
|
||||
div.jGrowl div.jGrowl-notify div.jGrowl-header{font-weight:bold}
|
||||
div.jGrowl div.jGrowl-notify div.jGrowl-close{float:right;cursor:pointer}
|
||||
div.jGrowl div.jGrowl-closer{width:400px;color:#808080;background-color:#121510;opacity:0.96;border:2px solid #B0B0B0;margin:5px 0;padding:4px 0;cursor:pointer;font-weight:bold;text-align:center;border-radius:6px}
|
||||
div.jGrowl div.jGrowl-closer.top{position:fixed;top:140px}
|
||||
div.jGrowl div.jGrowl-closer.top{position:fixed;top:130px}
|
||||
@media print{div.jGrowl{display:none}}
|
||||
.ui-dropdownchecklist{background:transparent;border:none;box-shadow:0 1px 0 #1c1c1c;outline:none;height:32px;line-height:32px;cursor:pointer}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #1c1c1c;display:inline-block;cursor:pointer;padding:1px 9px 1px 11px}
|
||||
|
||||
@@ -27,7 +27,7 @@ background-color:rgba(0, 0, 0, 0.4);position:fixed;left:0;right:0;top:0;bottom:0
|
||||
.sweet-alert.show-input input{display:block}
|
||||
.sweet-alert .sa-confirm-button-container{display:inline-block;position:relative}
|
||||
.sweet-alert .la-ball-fall{position:absolute;left:50%;top:50%;margin-left:-27px;margin-top:4px;opacity:0;visibility:hidden}
|
||||
.sweet-alert button{font-family:clear-sans;font-size:13px;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:26px 5px 0 5px;padding:10px 28px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:.125rem;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.sweet-alert button{font-family:clear-sans;font-size:13px;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:26px 5px 0 5px;padding:10px 20px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:.125rem;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.sweet-alert button:focus{}
|
||||
.sweet-alert button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.sweet-alert button:active{}
|
||||
|
||||
2
robots.txt
Normal file
2
robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
Reference in New Issue
Block a user