summaryrefslogtreecommitdiffstats
path: root/modules-available/statistics/api.inc.php
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available/statistics/api.inc.php')
-rw-r--r--modules-available/statistics/api.inc.php166
1 files changed, 119 insertions, 47 deletions
diff --git a/modules-available/statistics/api.inc.php b/modules-available/statistics/api.inc.php
index 30d1fda9..18a58a77 100644
--- a/modules-available/statistics/api.inc.php
+++ b/modules-available/statistics/api.inc.php
@@ -11,17 +11,17 @@ if (substr($ip, 0, 7) === '::ffff:') $ip = substr($ip, 7);
* Power/hw/usage stats
*/
-if ($type{0} === '~') {
+if ($type[0] === '~') {
// UUID is mandatory
$uuid = Request::post('uuid', '', 'string');
$macaddr = Request::post('macaddr', false, 'string');
if ($macaddr !== false) {
$macaddr = strtolower(str_replace(':', '-', $macaddr));
- if (strlen($macaddr) !== 17 || $macaddr{2} !== '-') {
+ if (strlen($macaddr) !== 17 || $macaddr[2] !== '-') {
$macaddr = false;
}
}
- if ($macaddr !== false && $uuid{8} !== '-' && substr($uuid, 0, 16) === '000000000000001-') {
+ if ($macaddr !== false && $uuid[8] !== '-' && substr($uuid, 0, 16) === '000000000000001-') {
$uuid = 'baad1d00-9491-4716-b98b-' . str_replace('-', '', $macaddr);
}
if (strlen($uuid) !== 36 || !preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i', $uuid)) {
@@ -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');
@@ -61,10 +62,26 @@ if ($type{0} === '~') {
if (!is_string($hostname) || $hostname === $ip) {
$hostname = '';
}
- $data = Util::cleanUtf8(Request::post('data', '', 'string'));
+ $json = false;
+ $data = Util::cleanUtf8(Request::post('json', '', 'string'));
+ if (!empty($data) && $data[0] === '{') {
+ $json = json_decode($data, true);
+ if (!is_array($json)) {
+ $json = false;
+ } else {
+ $json['cpu'] = [
+ 'sockets' => Request::post('sockets', 0, 'int'),
+ 'cores' => $realcores,
+ 'threads' => Request::post('vcores', 0, 'int'),
+ ];
+ }
+ }
+ if ($json === false) {
+ $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 +103,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");
@@ -118,9 +135,9 @@ if ($type{0} === '~') {
. ' id44mb = :id44mb,'
. ' live_tmpsize = 0, live_swapsize = 0, live_memsize = 0, live_cpuload = 255, live_cputemp = 0,'
. ' badsectors = :badsectors,'
- . ' data = :data,'
+ . ' data = ' . ($json !== false ? ':data' : "If(Left(data, 1) = '{', 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 +163,17 @@ 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
+ }
+
+ if ($json !== false) {
+ $ret = HardwareParser::parseMachine($uuid, $json);
+ if ($ret !== null) {
+ // This data is more accurate and ends up in the DB anyways, so use it for event filtering too
+ $new['id44mb'] = $ret['id44mb'];
+ $new['id45mb'] = $ret['id45mb'];
+ }
}
// Check for suspicious hardware changes
@@ -155,16 +182,31 @@ 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'];
+ } else {
+ // First boot, mock some important fields for event log filtering
+ $new['oldlastboot'] = 0;
+ $new['oldlastseen'] = 0;
+ $new['oldstate'] = 'OFFLINE';
}
+ unset($new['data']);
+ EventLog::applyFilterRules($type, $new);
+
// Write statistics data
} else if ($type === '~runstate') {
+
// Usage (occupied/free)
$sessionLength = 0;
$strUpdateBoottime = '';
@@ -174,10 +216,14 @@ if ($type{0} === '~') {
}
$used = Request::post('used', 0, 'integer');
$params = array(
- 'uuid' => $uuid,
+ 'machineuuid' => $uuid,
'oldlastseen' => $old['lastseen'],
'oldstate' => $old['state'],
);
+ if ($NOW - $old['lastseen'] < 10 && ($old['state'] === 'OFFLINE' || $old['state'] === 'STANDBY')) {
+ // Avoid racing calls to ~runstate updates while/after we send a ~poweroff or ~suspend
+ die("OK.\n");
+ }
if ($old['state'] === 'OFFLINE') {
// This should never happen -- we expect a poweron event before runstate, which would set the state to IDLE
// So it might be that the poweron event got lost, or that a couple of runstate events got lost, which
@@ -199,14 +245,18 @@ if ($type{0} === '~') {
'memfree', 'tmpfree', 'swapfree', 'id45free',
'cpuload', 'cputemp'] as $item) {
$liveVal = Request::post($item, false, 'int');
- if ($liveVal !== false) {
- $strUpdateBoottime .= ' live_' . $item . ' = :_' . $item . ', ';
+ if ($liveVal !== false && $liveVal >= 0) {
+ $strUpdateBoottime .= ' live_' . $item . ' = :live_' . $item . ', ';
if ($item === 'cpuload' || $item === 'cputemp') {
$liveVal = round($liveVal);
} else {
$liveVal = ceil($liveVal / 1024);
}
- $params['_' . $item] = $liveVal;
+ $max = ($item === 'cpuload') ? 100 : (2 ** 31);
+ if ($liveVal > $max) {
+ $liveVal = $max;
+ }
+ $params['live_' . $item] = $liveVal;
}
}
if (($runmode = Request::post('runmode', false, 'string')) !== false) {
@@ -222,7 +272,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 +285,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 +293,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 +303,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 +322,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)) {
@@ -279,24 +338,24 @@ if ($type{0} === '~') {
if (!array_key_exists('name', $screen))
continue;
// Filter bogus data
- $screen['name'] = Util::cleanUtf8($screen['name']);
- $port = Util::cleanUtf8($port);
+ $screen['name'] = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $screen['name']);
+ $port = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $port);
if (empty($screen['name']))
continue;
if (array_key_exists($screen['name'], $hwids)) {
$hwid = $hwids[$screen['name']];
} else {
- $hwid = (int)Database::insertIgnore('statistic_hw', 'hwid',
- array('hwtype' => DeviceType::SCREEN, 'hwname' => $screen['name']));
+ $hwid = Database::insertIgnore('statistic_hw', 'hwid',
+ ['hwtype' => HardwareInfo::SCREEN, 'hwname' => $screen['name']]);
$hwids[$screen['name']] = $hwid;
}
// Now add new entries
$keepPair[] = array($hwid, $port);
- $machinehwid = Database::insertIgnore('machine_x_hw', 'machinehwid', array(
+ $machinehwid = Database::insertIgnore('machine_x_hw', 'machinehwid', [
'hwid' => $hwid,
'machineuuid' => $uuid,
'devpath' => $port,
- ), array('disconnecttime' => 0));
+ ], ['disconnecttime' => 0]);
$validProps = array();
if (count($screen) > 1) {
// Screen has additional properties (resolution, size, etc.)
@@ -333,20 +392,27 @@ if ($type{0} === '~') {
Database::exec("UPDATE machine_x_hw x, statistic_hw h
SET x.disconnecttime = UNIX_TIMESTAMP()
WHERE x.machineuuid = :uuid AND x.hwid = h.hwid AND h.hwtype = :type AND x.disconnecttime = 0",
- array('uuid' => $uuid, 'type' => DeviceType::SCREEN));
+ array('uuid' => $uuid, 'type' => HardwareInfo::SCREEN));
} else {
// Some screens connected, make sure old entries get removed
Database::exec("UPDATE machine_x_hw x, statistic_hw h
SET x.disconnecttime = UNIX_TIMESTAMP()
- WHERE (x.hwid, x.devpath) NOT IN (:pairs) AND x.disconnecttime = 0 AND h.hwtype = :type
+ WHERE (x.hwid, x.devpath) NOT IN (:pairs) AND x.hwid = h.hwid AND x.disconnecttime = 0 AND h.hwtype = :type
AND x.machineuuid = :uuid", array(
'pairs' => $keepPair,
'uuid' => $uuid,
- 'type' => DeviceType::SCREEN,
+ 'type' => HardwareInfo::SCREEN,
));
}
+
+ // Benchmarking
+ Database::exec("INSERT INTO statistic (dateline, typeid, clientip, machineuuid, username, `data`)
+ VALUES (UNIX_TIMESTAMP(), :type, :ip, :uuid, '', '')",
+ ['type' => 'graphical-startup', 'ip' => $ip, 'uuid' => $uuid]);
}
+
} else if ($type === '~suspend') {
+
// Client entering suspend
if ($old === false) die("Unknown machine.\n");
if ($old['clientip'] !== $ip) {
@@ -357,10 +423,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 +448,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 +483,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} === '.') {
+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,21 +495,35 @@ 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,
+ '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);
+ }
}
/**
* @param array $old row from DB with client's old data
* @param array $new new data to be written
*/
-function checkHardwareChange($old, $new)
+function checkHardwareChange(array $old, array $new): void
{
if ($new['mbram'] !== 0) {
if ($new['mbram'] < 6200) {
@@ -463,10 +535,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']}'");
}
}
}