summaryrefslogtreecommitdiffstats
path: root/modules-available/statistics
diff options
context:
space:
mode:
authorSimon Rettberg2021-06-25 16:21:17 +0200
committerSimon Rettberg2021-06-25 16:21:17 +0200
commit32f0677dbca9e3347b931c1d0105eb37aa57e90d (patch)
treeddad4562e7ee8439a24e2462d44614692bb71d14 /modules-available/statistics
parentUpdate .idea (diff)
downloadslx-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.php90
-rw-r--r--modules-available/statistics/hooks/cron.inc.php16
-rw-r--r--modules-available/statistics/inc/devicetype.inc.php1
-rw-r--r--modules-available/statistics/page.inc.php12
-rw-r--r--modules-available/statistics/pages/replace.inc.php20
-rw-r--r--modules-available/statistics/permissions/permissions.json3
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