diff options
author | Simon Rettberg | 2021-06-25 16:21:17 +0200 |
---|---|---|
committer | Simon Rettberg | 2021-06-25 16:21:17 +0200 |
commit | 32f0677dbca9e3347b931c1d0105eb37aa57e90d (patch) | |
tree | ddad4562e7ee8439a24e2462d44614692bb71d14 /modules-available/statistics | |
parent | Update .idea (diff) | |
download | slx-admin-32f0677dbca9e3347b931c1d0105eb37aa57e90d.tar.gz slx-admin-32f0677dbca9e3347b931c1d0105eb37aa57e90d.tar.xz slx-admin-32f0677dbca9e3347b931c1d0105eb37aa57e90d.zip |
[eventlog] Add event filtering and notification system
Diffstat (limited to 'modules-available/statistics')
-rw-r--r-- | modules-available/statistics/api.inc.php | 90 | ||||
-rw-r--r-- | modules-available/statistics/hooks/cron.inc.php | 16 | ||||
-rw-r--r-- | modules-available/statistics/inc/devicetype.inc.php | 1 | ||||
-rw-r--r-- | modules-available/statistics/page.inc.php | 12 | ||||
-rw-r--r-- | modules-available/statistics/pages/replace.inc.php | 20 | ||||
-rw-r--r-- | modules-available/statistics/permissions/permissions.json | 3 |
6 files changed, 97 insertions, 45 deletions
diff --git a/modules-available/statistics/api.inc.php b/modules-available/statistics/api.inc.php index 974432c6..04614521 100644 --- a/modules-available/statistics/api.inc.php +++ b/modules-available/statistics/api.inc.php @@ -31,7 +31,8 @@ if ($type[0] === '~') { // External mode of operation? $mode = Request::post('mode', false, 'string'); $NOW = time(); - $old = Database::queryFirst('SELECT clientip, logintime, lastseen, lastboot, state, mbram, cpumodel, live_memfree, live_swapfree, live_tmpfree + $old = Database::queryFirst('SELECT clientip, locationid, logintime, lastseen, lastboot, state, mbram, + cpumodel, live_memfree, live_swapfree, live_tmpfree FROM machine WHERE machineuuid = :uuid', array('uuid' => $uuid)); if ($old !== false) { settype($old['logintime'], 'integer'); @@ -64,7 +65,7 @@ if ($type[0] === '~') { $data = Util::cleanUtf8(Request::post('data', '', 'string')); // Prepare insert/update to machine table $new = array( - 'uuid' => $uuid, + 'machineuuid'=> $uuid, 'macaddr' => $macaddr, 'clientip' => $ip, 'lastseen' => $NOW, @@ -86,7 +87,7 @@ if ($type[0] === '~') { $res = Database::exec('INSERT INTO machine ' . '(machineuuid, macaddr, clientip, firstseen, lastseen, logintime, position, lastboot, realcores, mbram,' . ' kvmstate, cpumodel, systemmodel, id44mb, badsectors, data, hostname, state) VALUES ' - . "(:uuid, :macaddr, :clientip, :firstseen, :lastseen, 0, '', :lastboot, :realcores, :mbram," + . "(:machineuuid, :macaddr, :clientip, :firstseen, :lastseen, 0, '', :lastboot, :realcores, :mbram," . ' :kvmstate, :cpumodel, :systemmodel, :id44mb, :badsectors, :data, :hostname, :state)', $new, true); if ($res === false) { die("Concurrent insert, ignored. (RESULT=0)\n"); @@ -120,7 +121,7 @@ if ($type[0] === '~') { . ' badsectors = :badsectors,' . ' data = :data,' . ' state = :state ' - . " WHERE machineuuid = :uuid AND state = :oldstate AND lastseen = :oldlastseen", $new); + . " WHERE machineuuid = :machineuuid AND state = :oldstate AND lastseen = :oldlastseen", $new); if ($res === 0) { die("Concurrent update, ignored. (RESULT=0)\n"); } @@ -146,7 +147,8 @@ if ($type[0] === '~') { if (($old === false || $old['clientip'] !== $ip) && Module::isAvailable('locations')) { // New, or ip changed (dynamic pool?), update subnetlicationid - Location::updateMapIpToLocation($uuid, $ip); + $loc = Location::updateMapIpToLocation($uuid, $ip); + $new['locationid'] = $loc; // For Filter Event } // Check for suspicious hardware changes @@ -155,16 +157,25 @@ if ($type[0] === '~') { // Log potential crash if ($old['state'] === 'IDLE' || $old['state'] === 'OCCUPIED') { - writeClientLog('machine-mismatch-poweron', 'Poweron event, but previous known state is ' . $old['state'] - . '. Free RAM: ' . Util::readableFileSize($old['live_memfree'], -1, 2) - . ', free Swap: ' . Util::readableFileSize($old['live_swapfree'], -1, 2) - . ', free ID44: ' . Util::readableFileSize($old['live_tmpfree'], -1, 2)); + if (Module::isAvailable('syslog')) { + ClientLog::write($new, 'machine-mismatch-poweron', + 'Poweron event, but previous known state is ' . $old['state'] + . '. Free RAM: ' . Util::readableFileSize($old['live_memfree'], -1, 2) + . ', free Swap: ' . Util::readableFileSize($old['live_swapfree'], -1, 2) + . ', free ID44: ' . Util::readableFileSize($old['live_tmpfree'], -1, 2)); + } } + // Add anything not present in $new from $old + $new += $old; } + $new['oldlastboot'] = $old['lastboot']; + EventLog::applyFilterRules($type, $new); + // Write statistics data } else if ($type === '~runstate') { + // Usage (occupied/free) $sessionLength = 0; $strUpdateBoottime = ''; @@ -174,7 +185,7 @@ if ($type[0] === '~') { } $used = Request::post('used', 0, 'integer'); $params = array( - 'uuid' => $uuid, + 'machineuuid' => $uuid, 'oldlastseen' => $old['lastseen'], 'oldstate' => $old['state'], ); @@ -200,13 +211,13 @@ if ($type[0] === '~') { 'cpuload', 'cputemp'] as $item) { $liveVal = Request::post($item, false, 'int'); if ($liveVal !== false) { - $strUpdateBoottime .= ' live_' . $item . ' = :_' . $item . ', '; + $strUpdateBoottime .= ' live_' . $item . ' = :live_' . $item . ', '; if ($item === 'cpuload' || $item === 'cputemp') { $liveVal = round($liveVal); } else { $liveVal = ceil($liveVal / 1024); } - $params['_' . $item] = $liveVal; + $params['live_' . $item] = $liveVal; } } if (($runmode = Request::post('runmode', false, 'string')) !== false) { @@ -222,7 +233,7 @@ if ($type[0] === '~') { $res = Database::exec('UPDATE machine SET lastseen = UNIX_TIMESTAMP(),' . $strUpdateBoottime . " logintime = 0, currentuser = NULL, state = 'IDLE' " - . " WHERE machineuuid = :uuid AND lastseen = :oldlastseen AND state = :oldstate", + . " WHERE machineuuid = :machineuuid AND lastseen = :oldlastseen AND state = :oldstate", $params); } elseif ($used === 1 && $old['state'] !== 'OCCUPIED') { // Machine is in use, was free before @@ -235,7 +246,7 @@ if ($type[0] === '~') { $res = Database::exec('UPDATE machine SET lastseen = UNIX_TIMESTAMP(),' . $strUpdateBoottime . " logintime = UNIX_TIMESTAMP(), currentuser = :user, currentsession = NULL, state = 'OCCUPIED' " - . " WHERE machineuuid = :uuid AND lastseen = :oldlastseen AND state = :oldstate", $params); + . " WHERE machineuuid = :machineuuid AND lastseen = :oldlastseen AND state = :oldstate", $params); } else { $res = 0; } @@ -243,7 +254,7 @@ if ($type[0] === '~') { // Nothing changed, simple lastseen update $res = Database::exec('UPDATE machine SET ' . $strUpdateBoottime - . ' lastseen = UNIX_TIMESTAMP() WHERE machineuuid = :uuid AND lastseen = :oldlastseen AND state = :oldstate', $params); + . ' lastseen = UNIX_TIMESTAMP() WHERE machineuuid = :machineuuid AND lastseen = :oldlastseen AND state = :oldstate', $params); } // Did we update, or was there a concurrent update? if ($res === 0) { @@ -253,7 +264,12 @@ if ($type[0] === '~') { if ($mode === false && $sessionLength > 0 && $sessionLength < 86400*2 && $old['logintime'] !== 0) { Statistics::logMachineState($uuid, $ip, Statistics::SESSION_LENGTH, $old['logintime'], $sessionLength); } + // Client Events + $params['newstate'] = ($used === 0) ? 'IDLE' : 'OCCUPIED'; + EventLog::applyFilterRules($type, $params + $old); + } elseif ($type === '~poweroff') { + if ($old === false) die("Unknown machine.\n"); if ($old['clientip'] !== $ip) { updateIp('poweroff', $uuid, $old, $ip); @@ -267,7 +283,11 @@ if ($type[0] === '~') { Database::exec("UPDATE machine SET logintime = 0, lastseen = UNIX_TIMESTAMP(), state = 'OFFLINE' WHERE machineuuid = :uuid AND state = :oldstate AND lastseen = :oldlastseen", array('uuid' => $uuid, 'oldlastseen' => $old['lastseen'], 'oldstate' => $old['state'])); + + EventLog::applyFilterRules($type, $old); + } elseif ($mode === false && $type === '~screens') { + if ($old === false) die("Unknown machine.\n"); $screens = Request::post('screen', false, 'array'); if (is_array($screens)) { @@ -346,7 +366,9 @@ if ($type[0] === '~') { )); } } + } else if ($type === '~suspend') { + // Client entering suspend if ($old === false) die("Unknown machine.\n"); if ($old['clientip'] !== $ip) { @@ -357,10 +379,13 @@ if ($type[0] === '~') { standbysem = If(standbysem < 6, standbysem + 1, 6) WHERE machineuuid = :uuid AND state = :oldstate AND lastseen = :oldlastseen", array('uuid' => $uuid, 'oldlastseen' => $old['lastseen'], 'oldstate' => $old['state'])); + EventLog::applyFilterRules($type, $old); } else { EventLog::info("[suspend] Client $uuid reported switch to standby when it wasn't powered on first. Was: " . $old['state']); } + } else if ($type === '~resume') { + // Waking up from suspend if ($old === false) die("Unknown machine.\n"); if ($old['clientip'] !== $ip) { @@ -379,6 +404,7 @@ if ($type[0] === '~') { Statistics::logMachineState($uuid, $ip, Statistics::SUSPEND_LENGTH, $lastSeen, $duration); } } + EventLog::applyFilterRules($type, $old); } else { EventLog::info("[resume] Client $uuid reported wakeup from standby when it wasn't logged as being in standby. Was: " . $old['state']); } @@ -413,21 +439,9 @@ function writeStatisticLog($type, $username, $data) )); } -function writeClientLog($type, $description) -{ - global $ip, $uuid; - Database::exec('INSERT INTO clientlog (dateline, logtypeid, clientip, machineuuid, description, extra) VALUES (UNIX_TIMESTAMP(), :type, :client, :uuid, :description, :longdesc)', array( - 'type' => $type, - 'client' => $ip, - 'description' => $description, - 'longdesc' => '', - 'uuid' => $uuid, - )); -} - - // For backwards compat, we require the . prefix if ($type[0] === '.') { + $data = false; if ($type === '.vmchooser-session') { $user = Util::cleanUtf8(Request::post('user', 'unknown', 'string')); $loguser = Request::post('loguser', 0, 'int') !== 0; @@ -437,14 +451,30 @@ if ($type[0] === '.') { Database::exec("UPDATE machine SET currentuser = :user, currentsession = :session WHERE clientip = :ip", compact('user', 'session', 'ip')); writeStatisticLog('.vmchooser-session-name', ($loguser ? $user : 'anonymous'), $sessionName); + $data = [ + 'clientip' => $ip, + 'user' => $user, + 'loguser' => $loguser, + 'sessionName' => $sessionName, + 'sessionUuid' => $sessionUuid, + 'session' => $session, + ]; } else { if (!isset($_POST['description'])) die('Missing options..'); $description = $_POST['description']; // and username embedded in message if (preg_match('#^\[([^\]]+)\]\s*(.*)$#m', $description, $out)) { writeStatisticLog($type, $out[1], $out[2]); + $data = [ + 'clientip' => $ip, + 'user' => $out[1], + 'description' => $out[2], + ]; } } + if ($data !== false) { + EventLog::applyFilterRules($type, $data); + } } /** @@ -463,10 +493,10 @@ function checkHardwareChange($old, $new) } if ($ram1 !== $ram2) { $word = $ram1 > $ram2 ? 'decreased' : 'increased'; - EventLog::warning('[poweron] Client ' . $new['uuid'] . ' (' . $new['clientip'] . "): RAM $word from {$ram1}GB to {$ram2}GB"); + EventLog::warning('[poweron] Client ' . $new['machineuuid'] . ' (' . $new['clientip'] . "): RAM $word from {$ram1}GB to {$ram2}GB"); } if (!empty($old['cpumodel']) && !empty($new['cpumodel']) && $new['cpumodel'] !== $old['cpumodel']) { - EventLog::warning('[poweron] Client ' . $new['uuid'] . ' (' . $new['clientip'] . "): CPU changed from '{$old['cpumodel']}' to '{$new['cpumodel']}'"); + EventLog::warning('[poweron] Client ' . $new['machineuuid'] . ' (' . $new['clientip'] . "): CPU changed from '{$old['cpumodel']}' to '{$new['cpumodel']}'"); } } } diff --git a/modules-available/statistics/hooks/cron.inc.php b/modules-available/statistics/hooks/cron.inc.php index aecc4e3b..7152b1da 100644 --- a/modules-available/statistics/hooks/cron.inc.php +++ b/modules-available/statistics/hooks/cron.inc.php @@ -27,17 +27,11 @@ function state_cleanup() $res = Database::simpleQuery("SELECT machineuuid, clientip, state, logintime, lastseen, live_memfree, live_swapfree, live_tmpfree FROM machine WHERE lastseen < If(state = 'STANDBY', $standby, $on) AND state <> 'OFFLINE'"); foreach ($res as $row) { - Database::exec('INSERT INTO clientlog (dateline, logtypeid, clientip, machineuuid, description, extra) - VALUES (UNIX_TIMESTAMP(), :type, :client, :uuid, :description, :longdesc)', array( - 'type' => 'machine-mismatch-cron', - 'client' => $row['clientip'], - 'description' => 'Client timed out, last known state is ' . $row['state'] - . '. Free RAM: ' . Util::readableFileSize($row['live_memfree'], -1, 2) - . ', free Swap: ' . Util::readableFileSize($row['live_swapfree'], -1, 2) - . ', free ID44: ' . Util::readableFileSize($row['live_tmpfree'], -1, 2), - 'longdesc' => '', - 'uuid' => $row['machineuuid'], - )); + ClientLog::write($row, 'machine-mismatch-cron', + 'Client timed out, last known state is ' . $row['state'] + . '. Free RAM: ' . Util::readableFileSize($row['live_memfree'], -1, 2) + . ', free Swap: ' . Util::readableFileSize($row['live_swapfree'], -1, 2) + . ', free ID44: ' . Util::readableFileSize($row['live_tmpfree'], -1, 2)); if ($row['state'] === 'OCCUPIED') { $length = $row['lastseen'] - $row['logintime']; if ($length > 0 && $length < 86400 * 7) { diff --git a/modules-available/statistics/inc/devicetype.inc.php b/modules-available/statistics/inc/devicetype.inc.php index 41ee237d..a01ec310 100644 --- a/modules-available/statistics/inc/devicetype.inc.php +++ b/modules-available/statistics/inc/devicetype.inc.php @@ -3,4 +3,5 @@ class DeviceType { const SCREEN = 'SCREEN'; + } diff --git a/modules-available/statistics/page.inc.php b/modules-available/statistics/page.inc.php index a16461f4..3e4aa9ce 100644 --- a/modules-available/statistics/page.inc.php +++ b/modules-available/statistics/page.inc.php @@ -2,7 +2,6 @@ class Page_Statistics extends Page { - private $query; private $show; /** @@ -22,6 +21,15 @@ class Page_Statistics extends Page $this->transformLegacyQuery(); } + /* + Dictionary::translate('submenu_projectors'); + Dictionary::translate('submenu_replace'); + */ + + foreach (['projectors', 'replace'] as $section) { + Dashboard::addSubmenu('?do=statistics&show=' . $section, Dictionary::translate('submenu_' . $section, true)); + } + $this->show = Request::any('show', false, 'string'); if ($this->show === false && Request::isGet()) { if (Request::get('uuid') !== false) { @@ -133,7 +141,7 @@ class Page_Statistics extends Page /** * @param bool $reboot true = reboot, false = shutdown */ - private function rebootControl($reboot) + private function rebootControl(bool $reboot) { if (!Module::isAvailable('rebootcontrol')) return; diff --git a/modules-available/statistics/pages/replace.inc.php b/modules-available/statistics/pages/replace.inc.php index 77f311ea..29e02292 100644 --- a/modules-available/statistics/pages/replace.inc.php +++ b/modules-available/statistics/pages/replace.inc.php @@ -5,6 +5,7 @@ class SubPage public static function doPreprocess() { + User::assertPermission('replace'); $action = Request::post('action', false, 'string'); if ($action === 'replace') { self::handleReplace(); @@ -22,6 +23,8 @@ class SubPage return; } $list = []; + $allowed = User::getAllowedLocations('replace'); + // Loop through passed machines, filter out unsuited pairs (both in use) and those without permission foreach ($replace as $p) { $split = explode('x', $p); if (count($split) !== 2) { @@ -29,13 +32,13 @@ class SubPage continue; } $entry = ['old' => $split[0], 'new' => $split[1]]; - $old = Database::queryFirst('SELECT lastseen FROM machine WHERE machineuuid = :old', + $old = Database::queryFirst('SELECT locationid, lastseen FROM machine WHERE machineuuid = :old', ['old' => $entry['old']]); if ($old === false) { Message::addError('unknown-machine', $entry['old']); continue; } - $new = Database::queryFirst('SELECT firstseen FROM machine WHERE machineuuid = :new', + $new = Database::queryFirst('SELECT locationid, firstseen FROM machine WHERE machineuuid = :new', ['new' => $entry['new']]); if ($new === false) { Message::addError('unknown-machine', $entry['new']); @@ -45,6 +48,16 @@ class SubPage Message::addWarning('ignored-both-in-use', $entry['old'], $entry['new']); continue; } + if (!in_array(0, $allowed)) { + if (!in_array($old['locationid'], $allowed)) { + Message::addWarning('ignored-no-permission', $entry['old']); + continue; + } + if (!in_array($new['locationid'], $allowed)) { + Message::addWarning('ignored-no-permission', $entry['new']); + continue; + } + } $entry['datelimit'] = min($new['firstseen'], $old['lastseen']); $list[] = $entry; } @@ -106,7 +119,10 @@ class SubPage FROM machine old INNER JOIN machine new ON (old.clientip = new.clientip AND old.lastseen < new.firstseen AND old.lastseen > $oldCutoff AND new.firstseen > $newCutoff) ORDER BY oldhost ASC, oldip ASC"); $list = []; + $allowed = User::getAllowedLocations('replace'); foreach ($res as $row) { + if (!in_array(0, $allowed) && (!in_array($row['oldlid'], $allowed) || !in_array($row['newlid'], $allowed))) + continue; $row['oldlastseen_s'] = Util::prettyTime($row['oldlastseen']); $row['newfirstseen_s'] = Util::prettyTime($row['newfirstseen']); $list[] = $row; diff --git a/modules-available/statistics/permissions/permissions.json b/modules-available/statistics/permissions/permissions.json index 663a8dc4..b27ca992 100644 --- a/modules-available/statistics/permissions/permissions.json +++ b/modules-available/statistics/permissions/permissions.json @@ -22,5 +22,8 @@ }, "view.list": { "location-aware": true + }, + "replace": { + "location-aware": true } }
\ No newline at end of file |