<?php
class Page_Statistics extends Page
{
private $show;
/**
* @var bool whether we have a SubPage from the pages/ subdir
*/
private $haveSubpage;
protected function doPreprocess()
{
User::load();
if (!User::isLoggedIn()) {
Message::addError('main.no-permission');
Util::redirect('?do=Main');
}
if (Request::isGet()) {
$this->transformLegacyQuery();
}
/*
Dictionary::translate('submenu_projectors');
Dictionary::translate('submenu_replace');
Dictionary::translate('submenu_hints');
*/
foreach (['projectors', 'replace', 'hints'] as $section) {
Dashboard::addSubmenu('?do=statistics&show=' . $section,
Dictionary::translate('submenu_' . $section));
}
$this->show = Request::any('show', false, 'string');
if ($this->show === false && Request::isGet()) {
if (Request::get('uuid') !== false) {
$this->show = 'machine';
} elseif (User::hasPermission('view.summary')) {
$this->show = 'summary';
} elseif (User::hasPermission('view.list')) {
$this->show = 'list';
} else {
User::assertPermission('view.summary');
}
}
if ($this->show !== false) {
$this->show = preg_replace('/[^a-z0-9_\-]/', '', $this->show);
if (!file_exists('modules/statistics/pages/' . $this->show . '.inc.php')) {
Message::addError('main.invalid-action', $this->show);
} else {
require_once 'modules/statistics/pages/' . $this->show . '.inc.php';
$this->haveSubpage = true;
SubPage::doPreprocess();
}
return;
}
if (!Request::isPost())
return;
// POST
$action = Request::post('action');
if ($action === 'setnotes') {
$uuid = Request::post('uuid', '', 'string');
$res = Database::queryFirst('SELECT locationid FROM machine WHERE machineuuid = :uuid',
array('uuid' => $uuid));
if ($res === false) {
Message::addError('unknown-machine', $uuid);
Util::redirect('?do=statistics');
}
User::assertPermission("machine.note.edit", (int)$res['locationid']);
$text = Request::post('content', null, 'string');
if (empty($text)) {
$text = null;
}
Database::exec('UPDATE machine SET notes = :text WHERE machineuuid = :uuid', array(
'uuid' => $uuid,
'text' => $text,
));
Message::addSuccess('notes-saved');
Util::redirect('?do=statistics&uuid=' . $uuid);
} elseif ($action === 'clear-machines') {
$this->deleteMachines(true);
} elseif ($action === 'delmachines') {
$this->deleteMachines(false);
Util::redirect('?do=statistics', true);
} elseif ($action === 'rebootmachines') {
$this->rebootControl(true);
} elseif ($action === 'shutdownmachines') {
$this->rebootControl(false);
} elseif ($action === 'wol') {
$this->wol();
} elseif ($action === 'benchmark') {
$this->vmstoreBenchmark();
} elseif ($action === 'prepare-exec') {
if (Module::isAvailable('rebootcontrol')) {
RebootControl::prepareExec();
}
} elseif (substr($action, 0, 12) === 'exec-preset-') {
if (Module::isAvailable('rebootcontrol')) {
RebootControl::prepareExec(substr($action, 12));
}
}
// Make sure we don't render any content for POST requests - should be handled above and then
// redirected properly
Util::redirect('?do=statistics');
}
private function transformLegacyQuery()
{
if (!Request::isGet())
return;
$query = Request::get('filters', false, 'string');
if ($query === false)
return;
foreach (explode(StatisticsFilter::LEGACY_DELIMITER, $query) as $q) {
if (!preg_match('/^\s*(\w+)\s*([<>=!~]{1,2})\s*(.*?)\s*$/', $q, $out))
continue;
$key = $out[1];
$_GET['filter'][$key] = '1';
$_GET['op'][$key] = $out[2];
$_GET['arg'][$key] = $out[3];
}
unset($_GET['filters']);
if (!empty($_GET['filter'])) {
Util::redirect('?' . http_build_query($_GET));
}
}
private function wol()
{
if (!Module::isAvailable('rebootcontrol'))
return;
$ids = Request::post('uuid', [], 'array');
$ids = array_values($ids);
if (empty($ids)) {
Message::addError('main.parameter-empty', 'uuid');
return;
}
$this->getAllowedMachines(".rebootcontrol.action.wol", $ids, $allowedMachines);
if (empty($allowedMachines))
return;
$taskid = RebootControl::wakeMachines($allowedMachines);
Util::redirect('?do=rebootcontrol&show=task&what=task&taskid=' . $taskid);
}
/**
* @param bool $reboot true = reboot, false = shutdown
*/
private function rebootControl(bool $reboot)
{
if (!Module::isAvailable('rebootcontrol'))
return;
$ids = Request::post('uuid', [], 'array');
$ids = array_values($ids);
if (empty($ids)) {
Message::addError('main.parameter-empty', 'uuid');
return;
}
$this->getAllowedMachines(".rebootcontrol.action." . ($reboot ? 'reboot' : 'shutdown'), $ids, $allowedMachines);
if (empty($allowedMachines))
return;
if ($reboot && Request::post('kexec', false)) {
$action = RebootControl::KEXEC_REBOOT;
} elseif ($reboot) {
$action = RebootControl::REBOOT;
} else {
$action = RebootControl::SHUTDOWN;
}
$task = RebootControl::execute($allowedMachines, $action, 0);
if (Taskmanager::isTask($task)) {
Util::redirect("?do=rebootcontrol&show=task&what=task&taskid=" . $task["id"]);
}
}
/**
* @param bool $reboot true = reboot, false = shutdown
*/
private function vmstoreBenchmark()
{
if (!Module::isAvailable('vmstore'))
return;
$ids = Request::post('uuid', [], 'array');
$ids = array_values($ids);
if (empty($ids)) {
Message::addError('main.parameter-empty', 'uuid');
return;
}
$this->getAllowedMachines(".vmstore.benchmark", $ids, $allowedMachines);
if (empty($allowedMachines))
return;
VmStoreBenchmark::prepareSelectDialog($allowedMachines);
}
private function getAllowedMachines($permission, $ids, &$allowedMachines)
{
$allowedLocations = User::getAllowedLocations($permission);
if (empty($allowedLocations)) {
Message::addError('main.no-permission');
Util::redirect('?do=statistics');
}
$res = Database::simpleQuery('SELECT machineuuid, clientip, macaddr, locationid FROM machine
WHERE machineuuid IN (:ids)', compact('ids'));
$ids = array_flip($ids);
$allowedMachines = [];
$seenLocations = [];
foreach ($res as $row) {
unset($ids[$row['machineuuid']]);
settype($row['locationid'], 'int');
if (in_array($row['locationid'], $allowedLocations)) {
$allowedMachines[] = $row;
} elseif (!isset($seenLocations[$row['locationid']])) {
Message::addError('locations.no-permission-location', $row['locationid']);
}
$seenLocations[$row['locationid']] = true;
}
if (!empty($ids)) {
Message::addWarning('unknown-machine', implode(', ', array_keys($ids)));
}
}
private function deleteMachines($soft)
{
$ids = Request::post('uuid', [], 'array');
$ids = array_values($ids);
if (empty($ids)) {
Message::addError('main.parameter-empty', 'uuid');
return;
}
$allowedLocations = User::getAllowedLocations("machine.delete");
if (empty($allowedLocations)) {
Message::addError('main.no-permission');
Util::redirect('?do=statistics');
}
$res = Database::simpleQuery('SELECT machineuuid, locationid FROM machine WHERE machineuuid IN (:ids)', compact('ids'));
$ids = array_flip($ids);
$delete = [];
foreach ($res as $row) {
unset($ids[$row['machineuuid']]);
if (in_array($row['locationid'], $allowedLocations)) {
$delete[] = $row['machineuuid'];
} else {
Message::addError('locations.no-permission-location', $row['locationid']);
}
}
if (!empty($delete)) {
if ($soft) {
// "Soft delete" -- keep all data, but set IP address to 0.0.0.0, so it will not be assigned to its
// old location anymore. Upon next boot some time in the future, the machine is hopefully relocated
// to somewhere else and will appear in a new location
Database::exec("UPDATE machine SET clientip = '0.0.0.0', fixedlocationid = NULL, subnetlocationid = NULL
WHERE machineuuid IN (:delete)", compact('delete'));
Message::addSuccess('cleared-n-machines', count($delete));
} else {
// Actually purge from DB
Database::exec('DELETE FROM machine WHERE machineuuid IN (:delete)', compact('delete'));
Message::addSuccess('deleted-n-machines', count($delete));
}
}
if (!empty($ids)) {
Message::addWarning('unknown-machine', implode(', ', array_keys($ids)));
}
}
protected function doRender()
{
if ($this->haveSubpage) {
SubPage::doRender();
return;
}
Message::addError('main.value-invalid', 'show', $this->show);
}
protected function doAjax()
{
if (!User::load())
return;
$action = Request::any('action');
if ($action === 'bios') {
require_once 'modules/statistics/pages/machine.inc.php';
SubPage::ajaxCheckBios();
return;
}
if ($action === 'json-lookup') {
$reply = [];
foreach (Request::post('list', [], 'array') as $item) {
$name = PciId::getPciId(PciId::AUTO, $item, true);
if ($name === false) {
$name = '?????';
}
$reply[$item] = $name;
}
header('Content-Type: application/json');
die(json_encode($reply));
}
$param = Request::any('lookup', false, 'string');
if ($param === false) {
die('No lookup given');
}
$add = '';
if (preg_match('/^([a-f0-9]{4}):([a-f0-9]{4})$/', $param, $out)) {
$add = ' (' . $param . ')';
}
$cached = PciId::getPciId(PciId::AUTO, $param, true);
if ($cached === false) {
$cached = 'Unknown';
}
echo $cached, $add;
exit;
}
}