summaryrefslogtreecommitdiffstats
path: root/modules-available/statistics
diff options
context:
space:
mode:
authorSimon Rettberg2017-12-01 13:42:04 +0100
committerSimon Rettberg2017-12-01 13:42:04 +0100
commit5393703f6e1485ddff94a50f63bcdd216ab629f4 (patch)
treece2db7130302bd4fb78b170e1fbd75496a1b4510 /modules-available/statistics
parentMerge remote-tracking branch 'origin/permission-manager' into permission-manager (diff)
parent[roomplanner] Sort already placed machines to the bottom (diff)
downloadslx-admin-5393703f6e1485ddff94a50f63bcdd216ab629f4.tar.gz
slx-admin-5393703f6e1485ddff94a50f63bcdd216ab629f4.tar.xz
slx-admin-5393703f6e1485ddff94a50f63bcdd216ab629f4.zip
Merge branch 'master' into permission-manager
Diffstat (limited to 'modules-available/statistics')
-rw-r--r--modules-available/statistics/api.inc.php207
-rw-r--r--modules-available/statistics/hooks/cron.inc.php25
-rw-r--r--modules-available/statistics/inc/filter.inc.php42
-rw-r--r--modules-available/statistics/inc/filterset.inc.php14
-rw-r--r--modules-available/statistics/inc/machine.inc.php5
-rw-r--r--modules-available/statistics/inc/statistics.inc.php51
-rw-r--r--modules-available/statistics/install.inc.php20
-rw-r--r--modules-available/statistics/lang/de/messages.json4
-rw-r--r--modules-available/statistics/lang/de/template-tags.json5
-rw-r--r--modules-available/statistics/lang/en/messages.json4
-rw-r--r--modules-available/statistics/lang/en/template-tags.json5
-rw-r--r--modules-available/statistics/page.inc.php93
-rw-r--r--modules-available/statistics/templates/clientlist.html18
-rw-r--r--modules-available/statistics/templates/machine-main.html23
-rw-r--r--modules-available/statistics/templates/machine-usage.html80
-rw-r--r--modules-available/statistics/templates/summary.html8
-rw-r--r--modules-available/statistics/templates/syslog.html2
17 files changed, 431 insertions, 175 deletions
diff --git a/modules-available/statistics/api.inc.php b/modules-available/statistics/api.inc.php
index c395220a..a614658a 100644
--- a/modules-available/statistics/api.inc.php
+++ b/modules-available/statistics/api.inc.php
@@ -34,7 +34,7 @@ if ($type{0} === '~') {
// External mode of operation?
$mode = Request::post('mode', false, 'string');
$NOW = time();
- $old = Database::queryFirst('SELECT clientip, logintime, lastseen, lastboot FROM machine WHERE machineuuid = :uuid', array('uuid' => $uuid));
+ $old = Database::queryFirst('SELECT clientip, logintime, lastseen, lastboot, state, mbram, cpumodel FROM machine WHERE machineuuid = :uuid', array('uuid' => $uuid));
if ($old !== false) {
settype($old['logintime'], 'integer');
settype($old['lastseen'], 'integer');
@@ -43,7 +43,7 @@ if ($type{0} === '~') {
// Handle event type
if ($mode === false && $type === '~poweron') {
// Poweron & hw stats
- $uptime = Request::post('uptime', '', 'integer');
+ $uptime = Request::post('uptime', 0, 'integer');
if (strlen($macaddr) > 17) die("Invalid MAC.\n");
if ($uptime < 0 || $uptime > 4000000) die("Implausible uptime.\n");
$realcores = Request::post('realcores', 0, 'integer');
@@ -64,6 +64,65 @@ if ($type{0} === '~') {
$hostname = '';
}
$data = Request::post('data', '', 'string');
+ // Prepare insert/update to machine table
+ $new = array(
+ 'uuid' => $uuid,
+ 'macaddr' => $macaddr,
+ 'clientip' => $ip,
+ 'lastseen' => $NOW,
+ 'lastboot' => $NOW - $uptime,
+ 'realcores' => $realcores,
+ 'mbram' => $mbram,
+ 'kvmstate' => $kvmstate,
+ 'cpumodel' => $cpumodel,
+ 'systemmodel'=> $systemmodel,
+ 'id44mb' => $id44mb,
+ 'badsectors' => $badsectors,
+ 'data' => $data,
+ 'state' => 'IDLE',
+ );
+ // Create/update machine entry
+ if ($old === false) {
+ $new['firstseen'] = $NOW;
+ $new['hostname'] = $hostname;
+ $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,"
+ . ' :kvmstate, :cpumodel, :systemmodel, :id44mb, :badsectors, :data, :hostname, :state)', $new, true);
+ if ($res === false) {
+ die("Concurrent insert, ignored. (RESULT=0)\n");
+ }
+ } else {
+ // Update
+ $moresql = ($uptime < 180 ? ' logintime = 0, currentuser = NULL, currentsession = NULL,' : '');
+ if (!empty($hostname)) {
+ $new['hostname'] = $hostname;
+ $moresql .= ' hostname = :hostname,';
+ }
+ $new['oldstate'] = $old['state'];
+ $new['oldlastseen'] = $old['lastseen'];
+ $res = Database::exec('UPDATE machine SET '
+ . ' macaddr = :macaddr,'
+ . ' clientip = :clientip,'
+ . ' lastseen = :lastseen,'
+ . ' lastboot = :lastboot,'
+ . $moresql
+ . ' realcores = :realcores,'
+ . ' mbram = :mbram,'
+ . ' kvmstate = :kvmstate,'
+ . ' cpumodel = :cpumodel,'
+ . ' systemmodel = :systemmodel,'
+ . ' id44mb = :id44mb,'
+ . ' badsectors = :badsectors,'
+ . ' data = :data,'
+ . ' state = :state '
+ . " WHERE machineuuid = :uuid AND state = :oldstate AND lastseen = :oldlastseen", $new);
+ if ($res === 0) {
+ die("Concurrent update, ignored. (RESULT=0)\n");
+ }
+ }
+ // Maybe log old crashed session
if ($uptime < 120) {
// See if we have a lingering session, create statistic entry if so
if ($old !== false && $old['logintime'] !== 0) {
@@ -93,49 +152,17 @@ if ($type{0} === '~') {
}
}
}
- // Create/update machine entry
- Database::exec('INSERT INTO machine '
- . '(machineuuid, macaddr, clientip, firstseen, lastseen, logintime, position, lastboot, realcores, mbram,'
- . ' kvmstate, cpumodel, systemmodel, id44mb, badsectors, data, hostname) VALUES '
- . "(:uuid, :macaddr, :clientip, :firstseen, :lastseen, 0, '', :lastboot, :realcores, :mbram,"
- . ' :kvmstate, :cpumodel, :systemmodel, :id44mb, :badsectors, :data, :hostname)'
- . ' ON DUPLICATE KEY UPDATE'
- . ' macaddr = VALUES(macaddr),'
- . ' clientip = VALUES(clientip),'
- . ' lastseen = VALUES(lastseen),'
- . ($uptime < 180 ? ' logintime = 0, currentuser = NULL, currentsession = NULL,' : '')
- . ' lastboot = VALUES(lastboot),'
- . ' realcores = VALUES(realcores),'
- . ' mbram = VALUES(mbram),'
- . ' kvmstate = VALUES(kvmstate),'
- . ' cpumodel = VALUES(cpumodel),'
- . ' systemmodel = VALUES(systemmodel),'
- . ' id44mb = VALUES(id44mb),'
- . ' badsectors = VALUES(badsectors),'
- . ' data = VALUES(data),'
- . " hostname = If(VALUES(hostname) = '', hostname, VALUES(hostname))", array(
- 'uuid' => $uuid,
- 'macaddr' => $macaddr,
- 'clientip' => $ip,
- 'firstseen' => $NOW,
- 'lastseen' => $NOW,
- 'lastboot' => $NOW - $uptime,
- 'realcores' => $realcores,
- 'mbram' => $mbram,
- 'kvmstate' => $kvmstate,
- 'cpumodel' => $cpumodel,
- 'systemmodel'=> $systemmodel,
- 'id44mb' => $id44mb,
- 'badsectors' => $badsectors,
- 'data' => $data,
- 'hostname' => $hostname,
- ));
if (($old === false || $old['clientip'] !== $ip) && Module::isAvailable('locations')) {
// New, or ip changed (dynamic pool?), update subnetlicationid
Location::updateMapIpToLocation($uuid, $ip);
}
+ // Check for suspicious hardware changes
+ if ($old !== false) {
+ checkHardwareChange($old, $new);
+ }
+
// Write statistics data
} else if ($type === '~runstate') {
@@ -147,7 +174,7 @@ if ($type{0} === '~') {
die("Address changed.\n");
}
$used = Request::post('used', 0, 'integer');
- if ($old['lastboot'] === 0 && $NOW - $old['lastseen'] > 300) {
+ if ($old['state'] === 'OFFLINE' && $NOW - $old['lastseen'] > 600) {
$strUpdateBoottime = ' lastboot = UNIX_TIMESTAMP(), ';
} else {
$strUpdateBoottime = '';
@@ -161,31 +188,42 @@ if ($type{0} === '~') {
}
$old['logintime'] = 0;
}
- $old['lastboot'] = 0;
}
// Figure out what's happening - state changes
- if ($used === 0 && $old['logintime'] !== 0) {
+ $params = array(
+ 'uuid' => $uuid,
+ 'oldlastseen' => $old['lastseen'],
+ 'oldstate' => $old['state'],
+ );
+ if ($used === 0 && $old['state'] !== 'IDLE') {
// Is not in use, was in use before
$sessionLength = $NOW - $old['logintime'];
- Database::exec('UPDATE machine SET lastseen = UNIX_TIMESTAMP(),'
+ $res = Database::exec('UPDATE machine SET lastseen = UNIX_TIMESTAMP(),'
. $strUpdateBoottime
- . ' logintime = 0, currentuser = NULL WHERE machineuuid = :uuid', array('uuid' => $uuid));
- } elseif ($used === 1 && $old['logintime'] === 0) {
+ . " logintime = 0, currentuser = NULL, state = 'IDLE' "
+ . " WHERE machineuuid = :uuid AND lastseen = :oldlastseen AND state = :oldstate",
+ $params);
+ } elseif ($used === 1 && $old['state'] !== 'OCCUPIED') {
// Machine is in use, was free before
if ($sessionLength !== 0 || $old['logintime'] === 0) {
// This event is a start of a new session, rather than an update
- Database::exec('UPDATE machine SET lastseen = UNIX_TIMESTAMP(),'
+ $params['user'] = Request::post('user', null, 'string');
+ $res = Database::exec('UPDATE machine SET lastseen = UNIX_TIMESTAMP(),'
. $strUpdateBoottime
- . ' logintime = UNIX_TIMESTAMP(), currentuser = :user WHERE machineuuid = :uuid', array(
- 'uuid' => $uuid,
- 'user' => Request::post('user', null, 'string'),
- ));
+ . " logintime = UNIX_TIMESTAMP(), currentuser = :user, currentsession = NULL, state = 'OCCUPIED' "
+ . " WHERE machineuuid = :uuid AND lastseen = :oldlastseen AND state = :oldstate", $params);
+ } else {
+ $res = 0;
}
} else {
// Nothing changed, simple lastseen update
- Database::exec('UPDATE machine SET '
+ $res = Database::exec('UPDATE machine SET '
. $strUpdateBoottime
- . ' lastseen = UNIX_TIMESTAMP() WHERE machineuuid = :uuid', array('uuid' => $uuid));
+ . ' lastseen = UNIX_TIMESTAMP() WHERE machineuuid = :uuid AND lastseen = :oldlastseen AND state = :oldstate', $params);
+ }
+ // Did we update, or was there a concurrent update?
+ if ($res === 0) {
+ die("Concurrent update, ignored. (RESULT=0)\n");
}
// 9) Log last session length if applicable
if ($mode === false && $sessionLength > 0 && $sessionLength < 86400*2 && $old['logintime'] !== 0) {
@@ -215,8 +253,11 @@ if ($type{0} === '~') {
));
}
}
- Database::exec('UPDATE machine SET logintime = 0, lastseen = UNIX_TIMESTAMP(), lastboot = 0 WHERE machineuuid = :uuid', array('uuid' => $uuid));
+ 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']));
} elseif ($mode === false && $type === '~screens') {
+ if ($old === false) die("Unknown machine.\n");
$screens = Request::post('screen', false, 'array');
if (is_array($screens)) {
// `devicetype`, `devicename`, `subid`, `machineuuid`
@@ -287,6 +328,47 @@ if ($type{0} === '~') {
}
}
+ } else if ($type === '~suspend') {
+ // Client entering suspend
+ if ($old === false) die("Unknown machine.\n");
+ if ($old['clientip'] !== $ip) {
+ EventLog::warning("[suspend] IP address of client $uuid seems to have changed ({$old['clientip']} -> $ip)");
+ die("Address changed.\n");
+ }
+ if ($NOW - $old['lastseen'] < 610 && $old['state'] !== 'OFFLINE') {
+ Database::exec("UPDATE machine SET lastseen = UNIX_TIMESTAMP(), state = 'STANDBY'
+ WHERE machineuuid = :uuid AND state = :oldstate AND lastseen = :oldlastseen",
+ array('uuid' => $uuid, 'oldlastseen' => $old['lastseen'], 'oldstate' => $old['state']));
+ } 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) {
+ EventLog::info("[resume] IP address of client $uuid seems to have changed ({$old['clientip']} -> $ip), allowed on resume.");
+ }
+ if ($old['state'] === 'STANDBY') {
+ $res = Database::exec("UPDATE machine SET state = 'IDLE', clientip = :ip, lastseen = UNIX_TIMESTAMP()
+ WHERE machineuuid = :uuid AND state = :oldstate AND lastseen = :oldlastseen",
+ array('uuid' => $uuid, 'ip' => $ip, 'oldlastseen' => $old['lastseen'], 'oldstate' => $old['state']));
+ // Write standby period length to statistic table
+ if ($mode === false && $res > 0 && $old['lastseen'] !== 0) {
+ $lastSeen = $old['lastseen'];
+ $duration = $NOW - $lastSeen;
+ if ($duration > 500 && $duration < 86400 * 14) {
+ Database::exec('INSERT INTO statistic (dateline, typeid, machineuuid, clientip, username, data)'
+ . " VALUES (:suspend, '~suspend-length', :uuid, :clientip, '', :length)", array(
+ 'suspend' => $lastSeen,
+ 'uuid' => $uuid,
+ 'clientip' => $ip,
+ 'length' => $duration
+ ));
+ }
+ }
+ } else {
+ EventLog::info("[resume] Client $uuid reported wakeup from standby when it wasn't logged as being in standby. Was: " . $old['state']);
+ }
} else {
die("INVALID ACTION '$type'\n");
}
@@ -315,6 +397,7 @@ function writeStatisticLog($type, $username, $data)
));
}
+
// For backwards compat, we require the . prefix
if ($type{0} === '.') {
if ($type === '.vmchooser-session') {
@@ -336,4 +419,22 @@ if ($type{0} === '.') {
}
}
+/**
+ * @param array $old row from DB with client's old data
+ * @param array $new new data to be written
+ */
+function checkHardwareChange($old, $new)
+{
+ if ($new['mbram'] !== 0) {
+ if ($new['mbram'] + 1000 < $old['mbram']) {
+ $ram1 = round($old['mbram'] / 512) / 2;
+ $ram2 = round($new['mbram'] / 512) / 2;
+ EventLog::warning('[poweron] Client ' . $new['uuid'] . ' (' . $new['clientip'] . "): RAM decreased 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']}'");
+ }
+ }
+}
+
echo "OK.\n";
diff --git a/modules-available/statistics/hooks/cron.inc.php b/modules-available/statistics/hooks/cron.inc.php
index 575ab6ba..4df7b0d4 100644
--- a/modules-available/statistics/hooks/cron.inc.php
+++ b/modules-available/statistics/hooks/cron.inc.php
@@ -1,18 +1,33 @@
<?php
-function logstats() {
+function logstats()
+{
$NOW = time();
$cutoff = $NOW - 86400 * 30;
- $online = $NOW - 610;
- $known = Database::queryFirst("SELECT Count(*) AS val FROM machine WHERE lastseen > $cutoff");
- $on = Database::queryFirst("SELECT Count(*) AS val FROM machine WHERE lastseen > $online");
- $used = Database::queryFirst("SELECT Count(*) AS val FROM machine WHERE lastseen > $online AND logintime <> 0");
+ $join = $where = '';
+ if (Module::get('runmode') !== false) {
+ $join = 'LEFT JOIN runmode r USING (machineuuid)';
+ $where = 'AND (r.isclient IS NULL OR r.isclient <> 0)';
+ }
+ $known = Database::queryFirst("SELECT Count(*) AS val FROM machine m $join WHERE m.lastseen > $cutoff $where");
+ $on = Database::queryFirst("SELECT Count(*) AS val FROM machine m $join WHERE m.state IN ('IDLE', 'OCCUPIED') $where");
+ $used = Database::queryFirst("SELECT Count(*) AS val FROM machine m $join WHERE m.state = 'OCCUPIED' $where");
Database::exec("INSERT INTO statistic (dateline, typeid, clientip, username, data) VALUES (:now, '~stats', '', '', :vals)", array(
'now' => $NOW,
'vals' => $known['val'] . '#' . $on['val'] . '#' . $used['val'],
));
}
+function state_cleanup()
+{
+ // Fix online state of machines that crashed
+ $standby = time() - 86400 * 2; // Reset standby machines after two days
+ $on = time() - 610; // Reset others after ~10 minutes
+ Database::exec("UPDATE machine SET state = 'OFFLINE' WHERE lastseen < If(state = 'STANDBY', $standby, $on) AND state <> 'OFFLINE'");
+}
+
+state_cleanup();
+
logstats();
if (mt_rand(1, 10) === 1) {
diff --git a/modules-available/statistics/inc/filter.inc.php b/modules-available/statistics/inc/filter.inc.php
index 0afce572..6e437a71 100644
--- a/modules-available/statistics/inc/filter.inc.php
+++ b/modules-available/statistics/inc/filter.inc.php
@@ -29,7 +29,7 @@ class Filter
$addendum = '';
/* check if we have to do some parsing*/
- if (Page_Statistics::$columns[$this->column]['type'] == 'date') {
+ if (Page_Statistics::$columns[$this->column]['type'] === 'date') {
$args[$key] = strtotime($this->argument);
} else {
$args[$key] = $this->argument;
@@ -180,21 +180,18 @@ class StateFilter extends Filter
{
public function __construct($operator, $argument)
{
- $this->operator = $operator;
- $this->argument = $argument;
+ parent::__construct(null, $operator, $argument);
}
public function whereClause(&$args, &$joins)
{
+ $map = [ 'on' => ['IDLE', 'OCCUPIED'], 'off' => ['OFFLINE'], 'idle' => ['IDLE'], 'occupied' => ['OCCUPIED'], 'standby' => ['STANDBY'] ];
$neg = $this->operator == '!=' ? 'NOT ' : '';
- if ($this->argument === 'on') {
- return " $neg (lastseen + 600 > UNIX_TIMESTAMP() ) ";
- } elseif ($this->argument === 'off') {
- return " $neg (lastseen + 600 < UNIX_TIMESTAMP() ) ";
- } elseif ($this->argument === 'idle') {
- return " $neg (lastseen + 600 > UNIX_TIMESTAMP() AND logintime = 0 ) ";
- } elseif ($this->argument === 'occupied') {
- return " $neg (lastseen + 600 > UNIX_TIMESTAMP() AND logintime <> 0 ) ";
+ if (array_key_exists($this->argument, $map)) {
+ global $unique_key;
+ $key = $this->column . '_arg' . ($unique_key++);
+ $args[$key] = $map[$this->argument];
+ return " machine.state $neg IN ( :$key ) ";
} else {
Message::addError('invalid-filter-argument', 'state', $this->argument);
return ' 1';
@@ -216,8 +213,10 @@ class LocationFilter extends Filter
$neg = $this->operator === '=' ? '' : 'NOT';
return "machine.locationid IS $neg NULL";
} else {
- $args['lid'] = $this->argument;
- return "machine.locationid {$this->operator} :lid";
+ global $unique_key;
+ $key = $this->column . '_arg' . ($unique_key++);
+ $args[$key] = $this->argument;
+ return "machine.locationid {$this->operator} :$key";
}
}
}
@@ -236,3 +235,20 @@ class SubnetFilter extends Filter
}
}
+class IsClientFilter extends Filter
+{
+ public function __construct($argument)
+ {
+ parent::__construct(null, null, $argument);
+ }
+
+ public function whereClause(&$args, &$joins)
+ {
+ if ($this->argument) {
+ $joins[] = ' LEFT JOIN runmode USING (machineuuid)';
+ return "(runmode.isclient <> 0 OR runmode.isclient IS NULL)";
+ }
+ $joins[] = ' INNER JOIN runmode USING (machineuuid)';
+ return "runmode.isclient = 0";
+ }
+}
diff --git a/modules-available/statistics/inc/filterset.inc.php b/modules-available/statistics/inc/filterset.inc.php
index c73feeef..25c5c8fa 100644
--- a/modules-available/statistics/inc/filterset.inc.php
+++ b/modules-available/statistics/inc/filterset.inc.php
@@ -2,6 +2,9 @@
class FilterSet
{
+ /**
+ * @var \Filter[]
+ */
private $filters;
private $sortDirection;
private $sortColumn;
@@ -39,7 +42,7 @@ class FilterSet
$where .= $sep . $filter->whereClause($args, $joins);
}
}
- $join = implode('', array_unique($joins));
+ $join = implode(' ', array_unique($joins));
$col = $this->sortColumn;
$isMapped = array_key_exists('map_sort', Page_Statistics::$columns[$col]);
@@ -72,4 +75,13 @@ class FilterSet
{
return $this->sortColumn;
}
+
+ public function filterNonClients()
+ {
+ if (Module::get('runmode') === false)
+ return;
+ // Runmode module exists, add filter
+ $this->filters[] = new IsClientFilter(true);
+ }
+
}
diff --git a/modules-available/statistics/inc/machine.inc.php b/modules-available/statistics/inc/machine.inc.php
index 8cb5e884..8605749b 100644
--- a/modules-available/statistics/inc/machine.inc.php
+++ b/modules-available/statistics/inc/machine.inc.php
@@ -51,6 +51,11 @@ class Machine
public $logintime;
/**
+ * @var string state of machine (OFFLINE, IDLE, OCCUPIED, STANDBY)
+ */
+ public $state;
+
+ /**
* @var string json data of position inside room (if any), null/empty otherwise
*/
public $position;
diff --git a/modules-available/statistics/inc/statistics.inc.php b/modules-available/statistics/inc/statistics.inc.php
index 1c9ebf07..2500f16f 100644
--- a/modules-available/statistics/inc/statistics.inc.php
+++ b/modules-available/statistics/inc/statistics.inc.php
@@ -7,17 +7,12 @@ class Statistics
private static $machineFields = false;
- /**
- * @param string $machineuuid
- * @param int $returnData
- * @return \Machine|false
- */
- public static function getMachine($machineuuid, $returnData)
+ private static function initFields($returnData)
{
if (self::$machineFields === false) {
$r = new ReflectionClass('Machine');
$props = $r->getProperties(ReflectionProperty::IS_PUBLIC);
- self::$machineFields = array_flip(array_map(function($e) { return $e->getName(); }, $props));
+ self::$machineFields = array_flip(array_map(function(/* @var ReflectionProperty $e */ $e) { return $e->getName(); }, $props));
}
if ($returnData === Machine::NO_DATA) {
unset(self::$machineFields['data']);
@@ -26,8 +21,19 @@ class Statistics
} else {
Util::traceError('Invalid $returnData option passed');
}
- $fields = implode(',', array_keys(self::$machineFields));
- $row = Database::queryFirst("SELECT * FROM machine WHERE machineuuid = :machineuuid", compact('machineuuid'));
+ return implode(',', array_keys(self::$machineFields));
+ }
+
+ /**
+ * @param string $machineuuid
+ * @param int $returnData What kind of data to return Machine::NO_DATA, Machine::RAW_DATA, ...
+ * @return \Machine|false
+ */
+ public static function getMachine($machineuuid, $returnData)
+ {
+ $fields = self::initFields($returnData);
+
+ $row = Database::queryFirst("SELECT $fields FROM machine WHERE machineuuid = :machineuuid", compact('machineuuid'));
if ($row === false)
return false;
$m = new Machine();
@@ -37,4 +43,31 @@ class Statistics
return $m;
}
+ /**
+ * @param string $ip
+ * @param int $returnData What kind of data to return Machine::NO_DATA, Machine::RAW_DATA, ...
+ * @param string $sort something like 'lastseen ASC' - not sanitized, don't pass user input!
+ * @return \Machine[] list of matches
+ */
+ public static function getMachinesByIp($ip, $returnData, $sort = false)
+ {
+ $fields = self::initFields($returnData);
+
+ if ($sort === false) {
+ $sort = '';
+ } else {
+ $sort = "ORDER BY $sort";
+ }
+ $res = Database::simpleQuery("SELECT $fields FROM machine WHERE clientip = :ip $sort", compact('ip'));
+ $list = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $m = new Machine();
+ foreach ($row as $key => $val) {
+ $m->{$key} = $val;
+ }
+ $list[] = $m;
+ }
+ return $list;
+ }
+
}
diff --git a/modules-available/statistics/install.inc.php b/modules-available/statistics/install.inc.php
index bfa342c4..4e2dfcca 100644
--- a/modules-available/statistics/install.inc.php
+++ b/modules-available/statistics/install.inc.php
@@ -36,6 +36,7 @@ $res[] = $machineCreate = tableCreate('machine', "
`logintime` int(10) unsigned NOT NULL,
`position` varchar(200) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`lastboot` int(10) unsigned NOT NULL,
+ `state` enum('OFFLINE', 'IDLE', 'OCCUPIED', 'STANDBY', 'IGNORED') NOT NULL DEFAULT 'OFFLINE',
`realcores` smallint(5) unsigned NOT NULL,
`mbram` int(10) unsigned NOT NULL,
`kvmstate` enum('UNKNOWN','UNSUPPORTED','DISABLED','ENABLED') NOT NULL,
@@ -51,6 +52,7 @@ $res[] = $machineCreate = tableCreate('machine', "
PRIMARY KEY (`machineuuid`),
KEY `macaddr` (`macaddr`),
KEY `clientip` (`clientip`),
+ KEY `state` (`state`),
KEY `realcores` (`realcores`),
KEY `mbram` (`mbram`),
KEY `kvmstate` (`kvmstate`),
@@ -198,6 +200,7 @@ if ($addTrigger) {
finalResponse(UPDATE_RETRY, 'Locations module not installed yet, retry later');
}
}
+ $res[] = UPDATE_DONE;
}
if ($machineHwCreate === UPDATE_DONE) {
@@ -217,12 +220,19 @@ if ($machineHwCreate === UPDATE_DONE) {
if ($ret === false) {
finalResponse(UPDATE_FAILED, 'Adding constraint to statistic_hw_prop failed: ' . Database::lastError());
}
+ $res[] = UPDATE_DONE;
}
-// Create response
-
-if (in_array(UPDATE_DONE, $res)) {
- finalResponse(UPDATE_DONE, 'Tables created successfully');
+// 2017-11-27: Add state column
+if (!tableHasColumn('machine', 'state')) {
+ $ret = Database::exec("ALTER TABLE `machine`
+ ADD COLUMN `state` enum('OFFLINE', 'IDLE', 'OCCUPIED', 'STANDBY', 'IGNORED') NOT NULL DEFAULT 'OFFLINE' AFTER `lastboot`,
+ ADD INDEX `state` (`state`)");
+ if ($ret === false) {
+ finalResponse(UPDATE_FAILED, 'Adding state column to machine table failed: ' . Database::lastError());
+ }
+ $res[] = UPDATE_DONE;
}
-finalResponse(UPDATE_NOOP, 'Everything already up to date');
+// Create response
+responseFromArray($res);
diff --git a/modules-available/statistics/lang/de/messages.json b/modules-available/statistics/lang/de/messages.json
index 8bdf9cfc..e3dff61c 100644
--- a/modules-available/statistics/lang/de/messages.json
+++ b/modules-available/statistics/lang/de/messages.json
@@ -1,6 +1,6 @@
{
- "invalid-filter": "Ung\u00fcltiger Filter",
"invalid-filter-argument": "Das Argument {{1}} ist nicht g\u00fcltig f\u00fcr den Filter {{0}}",
"invalid-filter-key": "{{0}} ist kein g\u00fcltiges Filterkriterium",
- "notes-saved": "Anmerkungen gespeichert"
+ "notes-saved": "Anmerkungen gespeichert",
+ "unknown-machine": "Unbekannte Rechner-ID {{0}}"
} \ No newline at end of file
diff --git a/modules-available/statistics/lang/de/template-tags.json b/modules-available/statistics/lang/de/template-tags.json
index 474d952a..56cf55d7 100644
--- a/modules-available/statistics/lang/de/template-tags.json
+++ b/modules-available/statistics/lang/de/template-tags.json
@@ -37,6 +37,7 @@
"lang_machineOccupied": "Der Rechner ist eingeschaltet und wird benutzt",
"lang_machineOccupiedBy": "In Verwendung durch",
"lang_machineOff": "Der Rechner ist ausgeschaltet, oder hat kein bwLehrpool gebootet",
+ "lang_machineStandby": "Im Standby",
"lang_machineSummary": "Zusammenfassung",
"lang_maximumAbbrev": "Max.",
"lang_memoryStats": "Arbeitsspeicher",
@@ -65,6 +66,8 @@
"lang_ramSlots": "Speicher-Slots",
"lang_realCores": "Kerne",
"lang_reallocatedSectors": "Defekte Sektoren",
+ "lang_runMode": "Betriebsmodus",
+ "lang_runmodeMachines": "Mit besonderem Betriebsmodus",
"lang_screens": "Bildschirme",
"lang_serialNo": "Serien-Nr",
"lang_showList": "Liste",
@@ -83,4 +86,4 @@
"lang_virtualCores": "Virtuelle Kerne",
"lang_when": "Wann",
"lang_withBadSectors": "Clients mit potentiell defekten Festplatten (mehr als 10 defekte Sektoren)"
-}
+} \ No newline at end of file
diff --git a/modules-available/statistics/lang/en/messages.json b/modules-available/statistics/lang/en/messages.json
index 40eac8c9..ae6c47af 100644
--- a/modules-available/statistics/lang/en/messages.json
+++ b/modules-available/statistics/lang/en/messages.json
@@ -1,6 +1,6 @@
{
- "invalid-filter": "Invalid filter",
"invalid-filter-argument": "{{1}} is not a vald argument for filter {{0}}",
"invalid-filter-key": "{{0}} is not a valid filter",
- "notes-saved": "Notes have been saved"
+ "notes-saved": "Notes have been saved",
+ "unknown-machine": "Unknown machine uuid {{0}}"
} \ No newline at end of file
diff --git a/modules-available/statistics/lang/en/template-tags.json b/modules-available/statistics/lang/en/template-tags.json
index f514b894..ab7a7d0a 100644
--- a/modules-available/statistics/lang/en/template-tags.json
+++ b/modules-available/statistics/lang/en/template-tags.json
@@ -37,6 +37,7 @@
"lang_machineOccupied": "Machine is powered on and in use",
"lang_machineOccupiedBy": "In use by",
"lang_machineOff": "Machine is powered down, or is not running bwLehrpool",
+ "lang_machineStandby": "In standby mode",
"lang_machineSummary": "Summary",
"lang_maximumAbbrev": "max.",
"lang_memoryStats": "Memory",
@@ -65,6 +66,8 @@
"lang_ramSlots": "Memory slots",
"lang_realCores": "Cores",
"lang_reallocatedSectors": "Bad sectors",
+ "lang_runMode": "Mode of operation",
+ "lang_runmodeMachines": "With special mode of operation",
"lang_screens": "Screens",
"lang_serialNo": "Serial no",
"lang_showList": "List",
@@ -83,4 +86,4 @@
"lang_virtualCores": "Virtual cores",
"lang_when": "When",
"lang_withBadSectors": "Clients with potentially bad HDDs (more than 10 reallocated sectors)"
-}
+} \ No newline at end of file
diff --git a/modules-available/statistics/page.inc.php b/modules-available/statistics/page.inc.php
index a003a303..d80d4614 100644
--- a/modules-available/statistics/page.inc.php
+++ b/modules-available/statistics/page.inc.php
@@ -106,6 +106,12 @@ class Page_Statistics extends Page
'op' => Page_Statistics::$op_nominal,
'type' => 'string',
'column' => true
+ ],
+ 'state' => [
+ 'op' => Page_Statistics::$op_nominal,
+ 'type' => 'enum',
+ 'column' => true,
+ 'values' => ['occupied', 'on']
]
];
if (Module::isAvailable('locations')) {
@@ -190,8 +196,6 @@ class Page_Statistics extends Page
} elseif ($action === 'addprojector' || $action === 'delprojector') {
$this->handleProjector($action);
}
- // Fix online state of machines that crashed -- TODO: Make cronjob for this
- Database::exec("UPDATE machine SET lastboot = 0 WHERE lastseen < UNIX_TIMESTAMP() - 610");
}
protected function doRender()
@@ -199,7 +203,12 @@ class Page_Statistics extends Page
$uuid = Request::get('uuid', false, 'string');
if ($uuid !== false) {
$this->showMachine($uuid);
+ return;
+ }
+ $show = Request::get('show', 'stat', 'string');
+ if ($show === 'projectors') {
+ $this->showProjectors();
return;
}
@@ -210,23 +219,19 @@ class Page_Statistics extends Page
}
$sortColumn = Request::any('sortColumn');
$sortDirection = Request::any('sortDirection');
- $filters = Filter::parseQuery($this->query);
+ $filters = Filter::parseQuery($this->query);
$filterSet = new FilterSet($filters);
$filterSet->setSort($sortColumn, $sortDirection);
-
- $show = Request::get('show', 'stat', 'string');
if ($show == 'list') {
Render::openTag('div', array('class' => 'row'));
$this->showFilter('list', $filterSet);
Render::closeTag('div');
$this->showMachineList($filterSet);
return;
- } elseif ($show === 'projectors') {
- $this->showProjectors();
- return;
}
+ $filterSet->filterNonClients();
Render::openTag('div', array('class' => 'row'));
$this->showFilter('stat', $filterSet);
$this->showSummary($filterSet);
@@ -328,8 +333,8 @@ class Page_Statistics extends Page
if ($known['val'] == 1) {
$this->redirectFirst($where, $join, $args);
}
- $on = Database::queryFirst("SELECT Count(*) AS val FROM machine $join WHERE lastboot <> 0 AND ($where)", $args);
- $used = Database::queryFirst("SELECT Count(*) AS val FROM machine $join WHERE lastboot <> 0 AND logintime <> 0 AND ($where)", $args);
+ $on = Database::queryFirst("SELECT Count(*) AS val FROM machine $join WHERE state IN ('IDLE', 'OCCUPIED') AND ($where)", $args);
+ $used = Database::queryFirst("SELECT Count(*) AS val FROM machine $join WHERE state = 'OCCUPIED' AND ($where)", $args);
$hdd = Database::queryFirst("SELECT Count(*) AS val FROM machine $join WHERE badsectors >= 10 AND ($where)", $args);
if ($on['val'] != 0) {
$usedpercent = round($used['val'] / $on['val'] * 100);
@@ -367,6 +372,10 @@ class Page_Statistics extends Page
}
$data['json'] = json_encode(array('labels' => $labels, 'datasets' => array($points1, $points2)));
$data['query'] = $this->query;
+ if (Module::get('runmode') !== false) {
+ $res = Database::queryFirst('SELECT Count(*) AS cnt FROM runmode');
+ $data['runmode'] = $res['cnt'];
+ }
// Draw
Render::addTemplate('summary', $data);
}
@@ -570,10 +579,16 @@ class Page_Statistics extends Page
$xtra = '';
if ($filterSet->isNoId44Filter()) {
- $xtra = ', data';
+ $xtra .= ', data';
+ }
+ if (Module::isAvailable('runmode')) {
+ $xtra .= ', runmode.module AS rmmodule';
+ if (strpos($join, 'runmode') === false) {
+ $join .= ' LEFT JOIN runmode USING (machineuuid) ';
+ }
}
- $res = Database::simpleQuery('SELECT machineuuid, macaddr, clientip, firstseen, lastseen,'
- . ' logintime, lastboot, realcores, mbram, kvmstate, cpumodel, id44mb, hostname, notes IS NOT NULL AS hasnotes,'
+ $res = Database::simpleQuery('SELECT machineuuid, macaddr, clientip, lastseen,'
+ . ' logintime, state, realcores, mbram, kvmstate, cpumodel, id44mb, hostname, notes IS NOT NULL AS hasnotes,'
. ' badsectors ' . $xtra . ' FROM machine'
. " $join WHERE $where $sort", $args);
$rows = array();
@@ -585,13 +600,7 @@ class Page_Statistics extends Page
} else {
$singleMachine = false;
}
- if ($row['lastboot'] == 0) {
- $row['state_off'] = true;
- } elseif ($row['logintime'] == 0) {
- $row['state_idle'] = true;
- } else {
- $row['state_occupied'] = true;
- }
+ $row['state_' . $row['state']] = true;
//$row['firstseen'] = date('d.m.Y H:i', $row['firstseen']);
$row['lastseen_int'] = $row['lastseen'];
$row['lastseen'] = date('d.m. H:i', $row['lastseen']);
@@ -725,24 +734,40 @@ class Page_Statistics extends Page
private function showMachine($uuid)
{
- $client = Database::queryFirst('SELECT machineuuid, locationid, macaddr, clientip, firstseen, lastseen, logintime, lastboot,'
+ $client = Database::queryFirst('SELECT machineuuid, locationid, macaddr, clientip, firstseen, lastseen, logintime, lastboot, state,'
. ' mbram, kvmstate, cpumodel, id44mb, data, hostname, currentuser, currentsession, notes FROM machine WHERE machineuuid = :uuid',
array('uuid' => $uuid));
+ if ($client === false) {
+ Message::addError('unknown-machine', $uuid);
+ return;
+ }
// Hack: Get raw collected data
if (Request::get('raw', false)) {
Header('Content-Type: text/plain; charset=utf-8');
die($client['data']);
}
+ // Runmode
+ if (Module::isAvailable('runmode')) {
+ $data = RunMode::getRunMode($uuid, RunMode::DATA_STRINGS);
+ if ($data !== false) {
+ $client += $data;
+ }
+ }
+ if (!isset($client['isclient'])) {
+ $client['isclient'] = true;
+ }
// Mangle fields
$NOW = time();
- if ($client['lastboot'] == 0) {
- $client['state_off'] = true;
- } elseif ($client['logintime'] == 0) {
- $client['state_idle'] = true;
+ if (!$client['isclient']) {
+ if ($client['state'] === 'IDLE') {
+ $client['state'] = 'OCCUPIED';
+ }
} else {
- $client['state_occupied'] = true;
- $this->fillSessionInfo($client);
+ if ($client['state'] === 'OCCUPIED') {
+ $this->fillSessionInfo($client);
+ }
}
+ $client['state_' . $client['state']] = true;
$client['firstseen_s'] = date('d.m.Y H:i', $client['firstseen']);
$client['lastseen_s'] = date('d.m.Y H:i', $client['lastseen']);
if ($client['lastboot'] == 0) {
@@ -750,7 +775,7 @@ class Page_Statistics extends Page
} else {
$uptime = $NOW - $client['lastboot'];
$client['lastboot_s'] = date('d.m.Y H:i', $client['lastboot']);
- if (!isset($client['state_off']) || !$client['state_off']) {
+ if ($client['state'] === 'IDLE' || $client['state'] === 'OCCUPIED') {
$client['lastboot_s'] .= ' (Up ' . floor($uptime / 86400) . 'd ' . gmdate('H:i', $uptime) . ')';
}
}
@@ -833,6 +858,8 @@ class Page_Statistics extends Page
$last = false;
$first = true;
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ if (!$client['isclient'] && $row['typeid'] === '~session-length')
+ continue; // Don't differentiate between session and idle for non-clients
if ($first && $row['dateline'] > $cutoff && $client['lastboot'] > $cutoff) {
// Special case: offline before
$spans['graph'] .= '<div style="background:#444;left:0%;width:' . round((min($row['dateline'], $client['lastboot']) - $cutoff) * $scale, 2) . '%">&nbsp;</div>';
@@ -865,12 +892,17 @@ class Page_Statistics extends Page
$color = '#e77';
}
$spans['graph'] .= '<div style="background:' . $color . ';left:' . round(($row['dateline'] - $cutoff) * $scale, 2) . '%;width:' . round(($row['data']) * $scale, 2) . '%">&nbsp;</div>';
- $spans['rows'][] = $row;
+ if ($client['isclient']) {
+ $spans['rows'][] = $row;
+ }
$last = $row;
}
if ($first && $client['lastboot'] > $cutoff) {
// Special case: offline before
$spans['graph'] .= '<div style="background:#444;left:0%;width:' . round(($client['lastboot'] - $cutoff) * $scale, 2) . '%">&nbsp;</div>';
+ } elseif ($first) {
+ // Not seen in last two weeks
+ $spans['graph'] .= '<div style="background:#444;left:0%;width:100%">&nbsp;</div>';
}
if (isset($client['state_occupied'])) {
$spans['graph'] .= '<div style="background:#e99;left:' . round(($client['logintime'] - $cutoff) * $scale, 2) . '%;width:' . round(($NOW - $client['logintime'] + 900) * $scale, 2) . '%">&nbsp;</div>';
@@ -891,6 +923,7 @@ class Page_Statistics extends Page
$spans['rows2'] = array_slice($spans['rows'], ceil(count($spans['rows']) / 2));
$spans['rows'] = array_slice($spans['rows'], 0, ceil(count($spans['rows']) / 2));
}
+ $spans['isclient'] = $client['isclient'];
Render::addTemplate('machine-usage', $spans);
// Any hdds?
if (!empty($hdds['hdds'])) {
@@ -922,7 +955,7 @@ class Page_Statistics extends Page
}
}
Render::addTemplate('syslog', array(
- 'clientip' => $client['clientip'],
+ 'machineuuid' => $client['machineuuid'],
'list' => $log,
));
}
diff --git a/modules-available/statistics/templates/clientlist.html b/modules-available/statistics/templates/clientlist.html
index ecfe622c..0b6fb37f 100644
--- a/modules-available/statistics/templates/clientlist.html
+++ b/modules-available/statistics/templates/clientlist.html
@@ -46,17 +46,21 @@
<tr>
<td data-sort-value="{{hostname}}" class="text-nowrap">
{{#hasnotes}}<span class="glyphicon glyphicon-exclamation-sign pull-right"></span>{{/hasnotes}}
- {{#state_off}}
+ {{#state_OFFLINE}}
<span class="glyphicon glyphicon-off" title="{{lang_machineOff}}"></span>
- {{/state_off}}
- {{#state_idle}}
+ {{/state_OFFLINE}}
+ {{#state_IDLE}}
<span class="glyphicon glyphicon-ok green" title="{{lang_machineIdle}}"></span>
- {{/state_idle}}
- {{#state_occupied}}
+ {{/state_IDLE}}
+ {{#state_OCCUPIED}}
<span class="glyphicon glyphicon-user red" title="{{lang_machineOccupied}}"></span>
- {{/state_occupied}}
+ {{/state_OCCUPIED}}
+ {{#state_STANDBY}}
+ <span class="glyphicon glyphicon-off green" title="{{lang_machineStandby}}"></span>
+ {{/state_STANDBY}}
<a href="?do=Statistics&amp;uuid={{machineuuid}}"><b>{{hostname}}</b></a>
<div class="small">{{machineuuid}}</div>
+ {{#rmmodule}}<div class="small">{{lang_runMode}}: <a class="slx-bold" href="?do=runmode&amp;module={{rmmodule}}">{{rmmodule}}</a></div>{{/rmmodule}}
</td>
<td data-sort-value="{{clientip}}"><b><a href="?do=Statistics&amp;show=list&amp;filters=subnet={{subnet}}">{{subnet}}</a>{{lastoctet}}</b><br>{{macaddr}}</td>
<td data-sort-value="{{lastseen_int}}" class="text-right">{{lastseen}}</td>
@@ -118,4 +122,4 @@ function toggleButton(v) {
$queryForm.submit();
}
-//--></script> \ No newline at end of file
+//--></script>
diff --git a/modules-available/statistics/templates/machine-main.html b/modules-available/statistics/templates/machine-main.html
index 74df80c4..14d388d3 100644
--- a/modules-available/statistics/templates/machine-main.html
+++ b/modules-available/statistics/templates/machine-main.html
@@ -50,13 +50,13 @@
<tr>
<td class="text-nowrap">{{lang_usageState}}</td>
<td>
- {{#state_off}}
+ {{#state_OFFLINE}}
<span class="glyphicon glyphicon-off"></span> {{lang_machineOff}}
- {{/state_off}}
- {{#state_idle}}
+ {{/state_OFFLINE}}
+ {{#state_IDLE}}
<span class="glyphicon glyphicon-ok green"></span> {{lang_machineIdle}}
- {{/state_idle}}
- {{#state_occupied}}
+ {{/state_IDLE}}
+ {{#state_OCCUPIED}}
{{#username}}
<span class="glyphicon glyphicon-user red"></span> {{lang_machineOccupiedBy}} <b>{{username}}</b>
{{/username}}
@@ -64,7 +64,10 @@
<span class="glyphicon glyphicon-user red"></span> {{lang_machineOccupied}}
{{/username}}
<div>{{logintime_s}}</div>
- {{/state_occupied}}
+ {{/state_OCCUPIED}}
+ {{#state_STANDBY}}
+ <span class="glyphicon glyphicon-off green"></span> {{lang_machineStandby}}
+ {{/state_STANDBY}}
{{#session}}
<div>
{{#lectureid}}
@@ -77,6 +80,14 @@
{{/session}}
</td>
</tr>
+ {{#modeid}}
+ <tr>
+ <td class="text-nowrap">{{lang_runMode}}</td>
+ <td>
+ <a href="?do={{modeid}}">{{moduleName}}</a> – {{modeName}}
+ </td>
+ </tr>
+ {{/modeid}}
</table>
</div>
</div>
diff --git a/modules-available/statistics/templates/machine-usage.html b/modules-available/statistics/templates/machine-usage.html
index ef969fc6..be435ee5 100644
--- a/modules-available/statistics/templates/machine-usage.html
+++ b/modules-available/statistics/templates/machine-usage.html
@@ -5,46 +5,50 @@
{{lang_usageDetails}}
</div>
<div class="panel-body">
- <div class="row">
- <div class="col-sm-6">
- <table class="table table-condensed">
- <tr>
- <th>{{lang_eventType}}</th>
- <th>{{lang_when}}</th>
- <th>{{lang_duration}}</th>
- </tr>
- {{#rows}}
- <tr>
- <td><span class="glyphicon glyphicon-{{glyph}}"></span></td>
- <td>{{from}}</td>
- <td>{{duration}}</td>
- </tr>
- {{/rows}}
- </table>
+ {{#isclient}}
+ <div class="row">
+ <div class="col-sm-6">
+ <table class="table table-condensed">
+ <tr>
+ <th>{{lang_eventType}}</th>
+ <th>{{lang_when}}</th>
+ <th>{{lang_duration}}</th>
+ </tr>
+ {{#rows}}
+ <tr>
+ <td><span class="glyphicon glyphicon-{{glyph}}"></span></td>
+ <td>{{from}}</td>
+ <td>{{duration}}</td>
+ </tr>
+ {{/rows}}
+ </table>
+ </div>
+ <div class="col-sm-6">
+ <table class="table table-condensed">
+ {{#hasrows2}}
+ <tr>
+ <th>{{lang_eventType}}</th>
+ <th>{{lang_when}}</th>
+ <th>{{lang_duration}}</th>
+ </tr>
+ {{/hasrows2}}
+ {{#rows2}}
+ <tr>
+ <td><span class="glyphicon glyphicon-{{glyph}}"></span></td>
+ <td>{{from}}</td>
+ <td>{{duration}}</td>
+ </tr>
+ {{/rows2}}
+ </table>
+ </div>
</div>
- <div class="col-sm-6">
- <table class="table table-condensed">
- {{#hasrows2}}
- <tr>
- <th>{{lang_eventType}}</th>
- <th>{{lang_when}}</th>
- <th>{{lang_duration}}</th>
- </tr>
- {{/hasrows2}}
- {{#rows2}}
- <tr>
- <td><span class="glyphicon glyphicon-{{glyph}}"></span></td>
- <td>{{from}}</td>
- <td>{{duration}}</td>
- </tr>
- {{/rows2}}
- </table>
- </div>
- </div>
+ {{/isclient}}
<div class="timebar">&nbsp;{{{graph}}}</div>
- <div>
- {{lang_timebarDesc}}
- </div>
+ {{#isclient}}
+ <div>
+ {{lang_timebarDesc}}
+ </div>
+ {{/isclient}}
</div>
</div>
</div>
diff --git a/modules-available/statistics/templates/summary.html b/modules-available/statistics/templates/summary.html
index 642c48fc..fe9559ed 100644
--- a/modules-available/statistics/templates/summary.html
+++ b/modules-available/statistics/templates/summary.html
@@ -1,6 +1,11 @@
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-body">
+ {{#runmode}}
+ <div class="pull-right">
+ <a href="?do=runmode">{{lang_runmodeMachines}}</a>: <b>{{runmode}}</b>
+ </div>
+ {{/runmode}}
<div>
{{lang_knownMachines}}: <b>{{known}}</b>&emsp;
<a href="?do=Statistics&amp;show=stat&amp;filters={{query}}~,~state=on">{{lang_onlineMachines}}</a>: <b>{{online}}</b>&emsp;
@@ -10,8 +15,9 @@
<div>
<span class="glyphicon glyphicon-exclamation-sign red"></span>
<a href="?do=Statistics&amp;show=list&amp;filters={{query}}~,~badsectors>=10">
- {{lang_withBadSectors}}: <b>{{badhdd}}</b>
+ {{lang_withBadSectors}}:
</a>
+ <b>{{badhdd}}</b>
</div>
{{/badhdd}}
</div>
diff --git a/modules-available/statistics/templates/syslog.html b/modules-available/statistics/templates/syslog.html
index c82cb8ac..968d32ab 100644
--- a/modules-available/statistics/templates/syslog.html
+++ b/modules-available/statistics/templates/syslog.html
@@ -20,7 +20,7 @@
{{/list}}
</tbody>
</table>
-<div class="pull-right"><a class="btn btn-default btn-sm" href="?do=SysLog&amp;ip={{clientip}}">{{lang_more}} &raquo;</a></div>
+<div class="pull-right"><a class="btn btn-default btn-sm" href="?do=SysLog&machineuuid={{machineuuid}}">{{lang_more}} &raquo;</a></div>
<div class="clearfix"></div>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">