Files
webgui/emhttp/plugins/dynamix/include/CPUset.php
2025-04-04 10:20:26 +01:00

222 lines
8.6 KiB
PHP

<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, 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 ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Helpers.php";
// add translations
$_SERVER['REQUEST_URI'] = 'settings';
require_once "$docroot/webGui/include/Translations.php";
$is_intel_cpu = is_intel_cpu();
$core_types = $is_intel_cpu ? get_intel_core_types() : [];
$cpus = explode(';',$_POST['cpus']??'');
$corecount = 0;
foreach ($cpus as $pair) {
unset($cpu1,$cpu2);
[$cpu1, $cpu2] = my_preg_split('/[,-]/',$pair);
if (!$cpu2) $corecount++; else $corecount=$corecount+2;
}
function scan($area, $text) {
return isset($area) ? strpos($area,$text)!==false : false;
}
function create($id, $name, $vcpu) {
// create the list of checkboxes. Make multiple rows when CPU cores are many ;)
global $cpus,$is_intel_cpu,$core_types;
$total = count($cpus);
$loop = floor(($total-1)/32)+1;
$text = [];
$unit = urlencode(str_replace([' ','(',')','[',']'],'',$name));
$name = urlencode($name);
echo "<td><span id='$id-$unit' style='color:#267CA8;display:none'><i class='fa fa-refresh fa-spin'></i> "._('updating')."</span></td>";
if ($id == "vm") $checkclass = "class=\"vcpu-".htmlspecialchars($name)."\""; else $checkclass = "";
for ($c = 0; $c < $loop; $c++) {
$max = ($c == $loop-1 ? ($total%32?:32) : 32);
for ($n = 0; $n < $max; $n++) {
unset($cpu1,$cpu2);
[$cpu1, $cpu2] = my_preg_split('/[,-]/',$cpus[$c*32+$n]);
$check1 = ($vcpu && in_array($cpu1, $vcpu)) ? 'checked':'';
$check2 = $cpu2 ? ($vcpu && (in_array($cpu2, $vcpu)) ? 'checked':''):'';
if (empty($text[$n])) $text[$n] = '';
if ($is_intel_cpu && count($core_types) > 0) $core_type = "{$core_types[$cpu1]}"; else $core_type = "";
$text[$n] .="<label title='$core_type' class='checkbox'><input type='checkbox' $checkclass name='$name:$cpu1' $check1><span class='checkmark'></span></label><br>";
if ($cpu2) {
if ($is_intel_cpu && count($core_types) > 0) $core_type = "{$core_types[$cpu2]}"; else $core_type = "";
$text[$n] .= "<label title='$core_type' class='checkbox'><input type='checkbox' $checkclass name='$name:$cpu2' $check2><span class='checkmark'></span></label><br>";
}
}
}
echo implode(array_map(function($t){return "<td>$t</td>";},$text));
}
switch ($_POST['id']??'') {
case 'vm':
// create the current vm assignments
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
$vms = $libvirt_running=='yes' ? ($lv->get_domains() ?: []) : [];
$user_prefs = '/boot/config/plugins/dynamix.vm.manager/userprefs.cfg';
// list vms per user preference
if (file_exists($user_prefs)) {
$prefs = parse_ini_file($user_prefs); $sort = [];
foreach ($vms as $vm) $sort[] = array_search($vm,$prefs) ?? 999;
array_multisort($sort,SORT_NUMERIC,$vms);
} else {
natcasesort($vms);
}
foreach ($vms as $vm) {
$uuid = $lv->domain_get_uuid($lv->get_domain_by_name($vm));
$cfg = domain_to_config($uuid);
echo "<tr><td>$vm</td>";
if ($cfg['domain']['vcpu'] >0 ) $disabled = "disabled"; else $disabled = "";
$vmenc = urlencode($vm);
$vcpuselect="<select id='vm-$vmenc-vcpu' name='$vmenc' class='narrow vcpus-$vmenc' title='"._("vcpu allocated to vm")."' $disabled>";
for ($i = 1; $i <= ($corecount); $i++) {
$vcpuselect .= mk_option($cfg['domain']['vcpus'], $i, $i);
}
$vcpuselect .= '</select>';
if ($disabled == "disabled") $buttontext = htmlspecialchars("Deselect All"); else $buttontext = htmlspecialchars("Select All");
echo "<td>$vcpuselect<input type=\"button\" value=\""._("$buttontext")."\" id=\"vmbtnvCPUSelect;$vmenc\" name=\"vmbtnvCPUSelect$vmenc\" onclick=\"vcpupins(this)\" /></td>";
create('vm', $vm, $cfg['domain']['vcpu']);
echo "</tr>";
}
// return the cpu assignments and available VM names
echo "\0".implode(';',array_map('urlencode',$vms));
break;
case 'ct':
// create the current container assignments
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
$DockerClient = new DockerClient();
$DockerTemplates = new DockerTemplates();
$containers = $DockerClient->getDockerContainers();
$allInfo = $DockerTemplates->getAllInfo();
$user_prefs = $dockerManPaths['user-prefs'];
$cts = []; foreach ($containers as $ct) $cts[] = $ct['Name'];
// list containers per user preference
if (file_exists($user_prefs)) {
$prefs = parse_ini_file($user_prefs); $sort = [];
foreach ($containers as $ct) $sort[] = array_search($ct['Name'],$prefs) ?? 999;
array_multisort($sort,SORT_NUMERIC,$containers);
unset($sort);
}
foreach ($containers as $ct) {
if ( ! is_file($allInfo[$ct['Name']]['template']) ) continue;
echo "<tr><td>{$ct['Name']}</td>";
create('ct', $ct['Name'], explode(',',$ct['CPUset']));
echo "</tr>";
}
// return the cpu assignments and available container names
echo "\0".implode(';',array_map('urlencode',$cts));
break;
case 'is':
if (is_file('/boot/syslinux/syslinux.cfg')) {
$menu = $i = 0;
$isol = "";
$isolcpus = [];
$bootcfg = file('/boot/syslinux/syslinux.cfg', FILE_IGNORE_NEW_LINES+FILE_SKIP_EMPTY_LINES);
$size = count($bootcfg);
// find the default section
while ($i < $size) {
if (scan($bootcfg[$i],'label ')) {
$n = $i + 1;
// find the current isolcpus setting
while (!scan($bootcfg[$n],'label ') && $n < $size) {
if (scan($bootcfg[$n],'menu default')) $menu = 1;
if (scan($bootcfg[$n],'append')) foreach (explode(' ',$bootcfg[$n]) as $cmd) if (scan($cmd,'isolcpus')) {$isol = explode('=',$cmd)[1]; break;}
$n++;
}
if ($menu) break; else $i = $n - 1;
}
$i++;
}
} elseif (is_file('/boot/grub/grub.cfg')) {
$isol = "";
$isolcpus = [];
$bootcfg = file('/boot/grub/grub.cfg', FILE_IGNORE_NEW_LINES);
// find the default section
$menu_entries = [];
foreach ($bootcfg as $line) {
if (preg_match('/set default=(\d+)/', $line, $match)) {
$bootentry = (int)$match[1];
break;
}
}
// split boot entries
foreach ($bootcfg as $line) {
if (strpos($line, 'menuentry ') === 0) {
$in_menuentry = true;
$current_entry = $line . "\n";
} elseif ($in_menuentry) {
$current_entry .= $line . "\n";
if (trim($line) === "}") {
$menu_entries[] = $current_entry;
$in_menuentry = false;
}
}
}
// search in selected menuentry
$menuentry = explode("\n", $menu_entries[$bootentry]);
// find the current isolcpus setting
if (scan($menu_entries[$bootentry],'linux ')) {
foreach ($menuentry as $cmd) {
if (scan($cmd,'isolcpus')) {
$isol = explode('=',$cmd)[1];
break;
}
}
}
}
if ($isol != '') {
// convert to individual numbers
foreach (explode(',',$isol) as $cpu) {
[$first,$last] = my_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 = '';
$cmdline = explode(' ',file_get_contents('/proc/cmdline'));
if (is_file('/boot/syslinux/syslinux.cfg')) {
$bootcfg = file('/boot/syslinux/syslinux.cfg',FILE_IGNORE_NEW_LINES+FILE_SKIP_EMPTY_LINES);
foreach ($cmdline as $cmd) if (scan($cmd,'isolcpus')) {$isolcpus_now = $cmd; break;}
$size = count($bootcfg);
$menu = $i = 0;
// find the default section
while ($i < $size) {
if (scan($bootcfg[$i],'label ')) {
$n = $i + 1;
// find the current isolcpus setting
while (!scan($bootcfg[$n],'label ') && $n < $size) {
if (scan($bootcfg[$n],'menu default')) $menu = 1;
if (scan($bootcfg[$n],'append')) foreach (explode(' ',$bootcfg[$n]) as $cmd) if (scan($cmd,'isolcpus')) {$isolcpus_new = $cmd; break;}
$n++;
}
if ($menu) break; else $i = $n - 1;
}
$i++;
}
} elseif (is_file('/boot/grub/grub.cfg')) {
$bootcfg = file('/boot/grub/grub.cfg', FILE_IGNORE_NEW_LINES);
}
echo $isolcpus_now==$isolcpus_new ? 0 : 1;
break;
}
?>