<?php
class SubPage
{
public static function doPreprocess()
{
User::assertPermission('hints');
}
public static function doRender()
{
$locs = User::getAllowedLocations('hints');
if (in_array(0, $locs)) {
$locs = [];
}
self::showLegacyCpu($locs);
self::showMemoryUpgrade($locs);
self::showSlowNics($locs);
self::showUnusedSpace($locs);
self::showMemorySlow($locs);
}
private static function isNonClientRunmode(string $machineUuid): bool
{
static $cache = null;
if ($cache === null) {
if (!Module::isAvailable('runmode')) {
$cache = [];
} else {
$cache = RunMode::getAllClients(false, false);
}
}
return isset($cache[$machineUuid]);
}
/**
* Machines that have less than 8GB of RAM. Highlight those
* that still have free memory slots.
*/
private static function showMemoryUpgrade(array $locs)
{
$q = new HardwareQuery(HardwareInfo::MAINBOARD);
if (!empty($locs)) {
$q->addMachineWhere('locationid', 'IN', $locs);
}
$q->addMachineWhere('lastseen', '>', strtotime('-60 days'));
$q->addLocalColumn('Memory Slot Occupied');
$q->addGlobalColumn('Memory Slot Count');
$q->addGlobalColumn('Memory Maximum Capacity');
$q->addMachineColumn('clientip');
$q->addMachineColumn('hostname');
$q->addMachineColumn('state');
$q->addLocalColumn('Memory Installed Capacity')->addCondition('<', 8 * 1024 * 1024 * 1024);
$list = [];
foreach ($q->query() as $row) {
if (self::isNonClientRunmode($row['machineuuid']))
continue;
if (HardwareParser::convertSize($row['Memory Installed Capacity'], 'M', false)
>= HardwareParser::convertSize($row['Memory Maximum Capacity'], 'M', false)) {
$row['size_class'] = 'danger';
}
if ($row['Memory Slot Occupied'] >= $row['Memory Slot Count']) {
$row['count_class'] = 'warning';
}
$row['icon'] = StatisticsStyling::machineStateToIcon($row['state']);
$list[] = $row;
}
if (empty($list))
return;
ArrayUtil::sortByColumn($list, 'hostname');
Render::addTemplate('hints-ram-upgrade', ['list' => $list]);
}
/**
* Show machines where RAM modules are running slower
* than their design speed.
*/
private static function showMemorySlow(array $locs)
{
$q = new HardwareQuery(HardwareInfo::RAM_MODULE);
if (!empty($locs)) {
$q->addMachineWhere('locationid', 'IN', $locs);
}
$q->addMachineWhere('lastseen', '>', strtotime('-60 days'));
//$q->addLocalColumn('Locator');
//$q->addLocalColumn('Bank Locator');
$q->addGlobalColumn('Form Factor');
$q->addGlobalColumn('Type');
$q->addGlobalColumn('Size');
$q->addGlobalColumn('Manufacturer');
$q->addLocalColumn('Serial Number');
$q->addMachineColumn('clientip');
$q->addMachineColumn('hostname');
$q->addMachineColumn('state');
$col = $q->addGlobalColumn('Speed');
$col->addCondition('>', $q->addLocalColumn('Configured Memory Speed'));
$list = [];
foreach ($q->query(['machineuuid', 'Size', 'Manufacturer', 'Speed', 'Configured Memory Speed']) as $row) {
// Sometimes configured speed reports as 2666 while rated speed is 2667
// Cast as these have a MT/s suffic, triggering a PHP notice about malformed numbers
if ((int)$row['Configured Memory Speed'] + 33 >= (int)$row['Speed'])
continue;
$row['icon'] = StatisticsStyling::machineStateToIcon($row['state']);
$list[] = $row;
}
if (empty($list))
return;
ArrayUtil::sortByColumn($list, 'hostname');
Render::addTemplate('hints-ram-underclocked', ['list' => $list]);
}
/**
* Show machines that have unpartitioned space available,
* and no ID44 or ID45.
*/
private static function showUnusedSpace(array $locs)
{
$id44 = $id45 = [];
// ID44
$q = new HardwareQuery(HardwareInfo::HDD);
if (!empty($locs)) {
$q->addMachineWhere('locationid', 'IN', $locs);
}
$q->addMachineWhere('lastseen', '>', strtotime('-60 days'));
$q->addMachineColumn('clientip');
$q->addMachineColumn('hostname');
$q->addLocalColumn('unused')->addCondition('>', 2000000000); // 2 GB
$q->addMachineWhere('id44mb', '<', 20000); // 20 GB
$q->addMachineColumn('state');
foreach ($q->query() as $row) {
$row['unused_s'] = Util::readableFileSize($row['unused']);
$row['id44mb_s'] = Util::readableFileSize($row['id44mb'], -1, 2);
$row['icon'] = StatisticsStyling::machineStateToIcon($row['state']);
$id44[] = $row;
}
// ID45
$q = new HardwareQuery(HardwareInfo::HDD);
if (!empty($locs)) {
$q->addMachineWhere('locationid', 'IN', $locs);
}
$q->addMachineWhere('lastseen', '>', strtotime('-60 days'));
$q->addMachineColumn('clientip');
$q->addMachineColumn('hostname');
$q->addLocalColumn('unused')->addCondition('>', 50000000000); // 50 GB
$q->addMachineWhere('id44mb', '>', 20000); // 20 GB
$q->addMachineWhere('id45mb', '<', 20000); // 20 GB
$q->addMachineColumn('state');
// Only suggest SSD based systems, caching on spinning rust is usually slower than GBit
$q->addGlobalColumn('rotation_rate')->addCondition('=', 0);
foreach ($q->query() as $row) {
$row['unused_s'] = Util::readableFileSize($row['unused']);
$row['id44mb_s'] = Util::readableFileSize($row['id44mb'], -1, 2);
$row['id45mb_s'] = Util::readableFileSize($row['id45mb'], -1, 2);
$row['icon'] = StatisticsStyling::machineStateToIcon($row['state']);
$id45[] = $row;
}
if (empty($id44) && empty($id45))
return;
ArrayUtil::sortByColumn($id44, 'hostname');
ArrayUtil::sortByColumn($id45, 'hostname');
Render::addTemplate('hints-hdd-grow', [
'id44' => $id44,
'id45' => $id45,
]);
}
private static function showSlowNics(array $locs)
{
$list = [];
$q = new HardwareQuery(HardwareInfo::MAINBOARD);
if (!empty($locs)) {
$q->addMachineWhere('locationid', 'IN', $locs);
}
$q->addMachineWhere('lastseen', '>', strtotime('-60 days'));
$q->addMachineColumn('clientip');
$q->addMachineColumn('hostname');
$q->addMachineColumn('state');
$q->addLocalColumn('nic-speed')->addCondition('<', 1000);
$q->addLocalColumn('nic-duplex');
foreach ($q->query() as $row) {
if ($row['nic-speed'] == 0) {
$row['nic-speed'] = '???';
}
$row['icon'] = StatisticsStyling::machineStateToIcon($row['state']);
$list[] = $row;
}
if (empty($list))
return;
ArrayUtil::sortByColumn($list, 'hostname');
Render::addTemplate('hints-nic-speed', ['list' => $list]);
}
/**
* Show machines that have a CPU that is only supported by VMware 12.5.x,
* but not newer versions.
*/
private static function showLegacyCpu(array $locs)
{
$list = [];
$q = new HardwareQuery(HardwareInfo::CPU);
if (!empty($locs)) {
$q->addMachineWhere('locationid', 'IN', $locs);
}
$q->addMachineWhere('lastseen', '>', strtotime('-60 days'));
$q->addMachineColumn('clientip');
$q->addMachineColumn('hostname');
$q->addMachineColumn('state');
$q->addMachineColumn('cpumodel');
$q->addGlobalColumn('vmx-legacy')->addCondition('<>', 0);
foreach ($q->query() as $row) {
$row['icon'] = StatisticsStyling::machineStateToIcon($row['state']);
$list[] = $row;
}
if (empty($list))
return;
ArrayUtil::sortByColumn($list, 'hostname');
Render::addTemplate('hints-cpu-legacy', ['list' => $list]);
}
}