summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--inc/dictionary.inc.php11
-rw-r--r--inc/render.inc.php4
-rw-r--r--inc/util.inc.php5
-rw-r--r--modules-available/locationinfo/inc/coursebackend.inc.php2
-rw-r--r--modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php7
-rw-r--r--modules-available/locationinfo/lang/de/template-tags.json3
-rw-r--r--modules-available/locationinfo/lang/en/template-tags.json3
-rw-r--r--modules-available/locationinfo/page.inc.php4
-rwxr-xr-xmodules-available/locationinfo/templates/frontend-default.html11
-rw-r--r--modules-available/locationinfo/templates/frontend-summary.html9
-rw-r--r--modules-available/statistics/api.inc.php115
-rw-r--r--modules-available/statistics/hooks/cron.inc.php25
-rw-r--r--modules-available/statistics/inc/filter.inc.php16
-rw-r--r--modules-available/statistics/inc/parser.inc.php10
-rw-r--r--modules-available/statistics/inc/statistics.inc.php17
-rw-r--r--modules-available/statistics/install.inc.php17
-rw-r--r--modules-available/statistics/lang/de/template-tags.json4
-rw-r--r--modules-available/statistics/lang/en/template-tags.json4
-rw-r--r--modules-available/statistics/page.inc.php122
-rw-r--r--modules-available/statistics/style.css32
-rw-r--r--modules-available/statistics/templates/filterbox.html5
-rw-r--r--modules-available/statistics/templates/machine-main.html32
-rw-r--r--modules-available/systemstatus/page.inc.php2
-rw-r--r--style/default.css2
24 files changed, 316 insertions, 146 deletions
diff --git a/inc/dictionary.inc.php b/inc/dictionary.inc.php
index fcbfdfb8..935d1f4e 100644
--- a/inc/dictionary.inc.php
+++ b/inc/dictionary.inc.php
@@ -30,10 +30,15 @@ class Dictionary
if ($lang !== false && in_array($lang, self::$languages)) {
setcookie('lang', $lang, time() + 60 * 60 * 24 * 30 * 12);
$url = Request::get('url');
- if ($url === false && isset($_SERVER['HTTP_REFERER']))
+ if ($url === false && isset($_SERVER['HTTP_REFERER'])) {
$url = $_SERVER['HTTP_REFERER'];
- if ($url === false)
- $url = '?do=Main';
+ }
+ $parts = parse_url($url);
+ if ($url === false || $parts === false || empty($parts['query'])) {
+ $url = '?do=main';
+ } else {
+ $url = '?' . $parts['query'];
+ }
Util::redirect($url);
}
diff --git a/inc/render.inc.php b/inc/render.inc.php
index 4b1d3643..4da0567e 100644
--- a/inc/render.inc.php
+++ b/inc/render.inc.php
@@ -213,7 +213,7 @@ class Render
* @param string $module name of module to load template from; defaults to currently active module
* @return string Rendered template
*/
- public static function parse($template, $params = false, $module = false)
+ public static function parse($template, $params = false, $module = false, $lang = false)
{
if ($module === false && class_exists('Page')) {
$module = Page::getModule()->getIdentifier();
@@ -228,7 +228,7 @@ class Render
}
// Now find all language tags in this array
if (preg_match_all('/{{\s*(lang_.+?)\s*}}/', $html, $out) > 0) {
- $dictionary = Dictionary::getArray($module, 'template-tags');
+ $dictionary = Dictionary::getArray($module, 'template-tags', $lang);
$fallback = false;
foreach ($out[1] as $tag) {
if ($fallback === false && empty($dictionary[$tag])) {
diff --git a/inc/util.inc.php b/inc/util.inc.php
index 1a5cbefe..e459cc46 100644
--- a/inc/util.inc.php
+++ b/inc/util.inc.php
@@ -234,9 +234,10 @@ SADFACE;
*
* @param float|int $bytes numeric value of the filesize to make readable
* @param int $decimals number of decimals to show, -1 for automatic
+ * @param int $shift how many units to skip, i.e. if you pass in KiB or MiB
* @return string human readable string representing the given file size
*/
- public static function readableFileSize($bytes, $decimals = -1)
+ public static function readableFileSize($bytes, $decimals = -1, $shift = 0)
{
$bytes = round($bytes);
static $sz = array('Byte', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB');
@@ -249,7 +250,7 @@ SADFACE;
$decimals = 2 - floor(strlen((int)$bytes) - 1);
}
}
- return sprintf("%.{$decimals}f", $bytes) . "\xe2\x80\x89" . $sz[$factor];
+ return sprintf("%.{$decimals}f", $bytes) . "\xe2\x80\x89" . $sz[$factor + $shift];
}
public static function sanitizeFilename($name)
diff --git a/modules-available/locationinfo/inc/coursebackend.inc.php b/modules-available/locationinfo/inc/coursebackend.inc.php
index 1da0086a..dcd92f6f 100644
--- a/modules-available/locationinfo/inc/coursebackend.inc.php
+++ b/modules-available/locationinfo/inc/coursebackend.inc.php
@@ -334,7 +334,7 @@ abstract class CourseBackend
{
$cleanresponse = preg_replace('/(<\/?)(\w+):([^>]*>)/', '$1$2$3', $response);
try {
- $xml = new SimpleXMLElement($cleanresponse);
+ $xml = @new SimpleXMLElement($cleanresponse); // This spams before throwing exception
} catch (Exception $e) {
$this->error = 'Could not parse reply as XML, got ' . get_class($e) . ': ' . $e->getMessage();
if (CONFIG_DEBUG) {
diff --git a/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php b/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php
index 22b1d8fb..c71623b3 100644
--- a/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php
+++ b/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php
@@ -271,6 +271,7 @@ class CourseBackend_HisInOne extends CourseBackend
$eventDetails = array_merge($eventDetails, $event);
}
$name = false;
+ $now = time();
foreach ($eventDetails as $event) {
foreach (array('/hisdefaulttext',
'/hisshorttext',
@@ -293,6 +294,12 @@ class CourseBackend_HisInOne extends CourseBackend
foreach ($planElements as $planElement) {
if (empty($planElement['hisplannedDates']))
continue;
+ $checkDate = $this->getArrayPath($planElement, '/hisplannedDates/hisplannedDate/hisenddate');
+ if (!empty($checkDate) && strtotime($checkDate[0]) + 86400 < $now)
+ continue; // Course ended
+ $checkDate = $this->getArrayPath($planElement, '/hisplannedDates/hisplannedDate/hisstartdate');
+ if (!empty($checkDate) && strtotime($checkDate[0]) - 86400 > $now)
+ continue; // Course didn't start yet
$unitPlannedDates = $this->getArrayPath($planElement,
'/hisplannedDates/hisplannedDate/hisindividualDates/hisindividualDate');
if ($unitPlannedDates === false) {
diff --git a/modules-available/locationinfo/lang/de/template-tags.json b/modules-available/locationinfo/lang/de/template-tags.json
index 03eb63a5..f9c7fad5 100644
--- a/modules-available/locationinfo/lang/de/template-tags.json
+++ b/modules-available/locationinfo/lang/de/template-tags.json
@@ -30,7 +30,8 @@
"lang_error": "Fehler",
"lang_expertMode": "Expertenmodus",
"lang_fourLocsHint": "Hier k\u00f6nnen Sie bis zu vier Orte ausw\u00e4hlen, die in diesem Panel angezeigt werden.",
- "lang_free": "Frei",
+ "lang_free": "Geöffnet",
+ "lang_for": "für",
"lang_general": "Allgemein",
"lang_ignoreSslTooltip": "Akzeptiere ung\u00fcltige, abgelaufene oder selbstsignierte SSL-Zertifikate",
"lang_insecureSsl": "Unsicheres SSL",
diff --git a/modules-available/locationinfo/lang/en/template-tags.json b/modules-available/locationinfo/lang/en/template-tags.json
index 1b5ab0fd..5bbe3775 100644
--- a/modules-available/locationinfo/lang/en/template-tags.json
+++ b/modules-available/locationinfo/lang/en/template-tags.json
@@ -30,7 +30,8 @@
"lang_error": "Error",
"lang_expertMode": "Expert mode",
"lang_fourLocsHint": "You can pick up to four locations that will be shown in this panel.",
- "lang_free": "Free",
+ "lang_free": "Open",
+ "lang_for": "for",
"lang_general": "General",
"lang_ignoreSslTooltip": "Accept invalid, expired or self-signed ssl certificates",
"lang_insecureSsl": "Insecure SSL",
diff --git a/modules-available/locationinfo/page.inc.php b/modules-available/locationinfo/page.inc.php
index 8ea18940..7be875d0 100644
--- a/modules-available/locationinfo/page.inc.php
+++ b/modules-available/locationinfo/page.inc.php
@@ -1002,7 +1002,7 @@ class Page_LocationInfo extends Page
'language' => $config['language'],
);
- die(Render::parse('frontend-default', $data));
+ die(Render::parse('frontend-default', $data, $module = false, $lang = $config['language']));
}
if ($type === 'SUMMARY') {
@@ -1014,7 +1014,7 @@ class Page_LocationInfo extends Page
'language' => $config['language'],
);
- die(Render::parse('frontend-summary', $data));
+ die(Render::parse('frontend-summary', $data, $module = false, $lang = $config['language']));
}
http_response_code(500);
diff --git a/modules-available/locationinfo/templates/frontend-default.html b/modules-available/locationinfo/templates/frontend-default.html
index 4dee8ef7..cbb765d0 100755
--- a/modules-available/locationinfo/templates/frontend-default.html
+++ b/modules-available/locationinfo/templates/frontend-default.html
@@ -352,6 +352,7 @@ optional:
<span data-tag="room">{{lang_room}}</span>
<span data-tag="closed">{{lang_closed}}</span>
<span data-tag="free">{{lang_free}}</span>
+ <span data-tag="for">{{lang_for}}</span>
<span data-tag="shortSun">{{lang_shortSun}}</span>
<span data-tag="shortMon">{{lang_shortMon}}</span>
<span data-tag="shortTue">{{lang_shortTue}}</span>
@@ -1151,7 +1152,7 @@ optional:
*/
function SetFreeSeats(room) {
// if room has no allowed value, set text in the box to -
- room.$.seatsCounter.text(room.freePcs >= 0 ? room.freePcs : '-');
+ room.$.seatsCounter.text(room.freePcs >= 0 ? room.freePcs : '\u2014');
room.$.seatsCounter.data('state', JSON.stringify(room.state));
if (room.freePcs > 0 && room.state && room.state.free) {
room.$.seatsBackground.css('background-color', '#250');
@@ -1174,8 +1175,6 @@ optional:
var seats = room.freePcs;
if (tmp.state === 'closed' || tmp.state === 'CalendarEvent' || tmp.state === 'Free') {
newTime = GetTimeDiferenceAsString(tmp.end, MyDate(), globalConfig);
- } else if (!same) {
- newTime = '';
}
if (tmp.state === "closed") {
if (!same) newText = t("closed");
@@ -1183,16 +1182,14 @@ optional:
if (!same) newText = tmp.title;
// whilst event is running set freePcs to -, hopefully not breaking anything else with this
room.freePcs = "-";
- } else if (tmp.state === "Free") {
- if (!same) newText = t("free");
- } else if (tmp.state === "FreeNoEnd") {
+ } else if (tmp.state === "Free" || tmp.state === "FreeNoEnd") {
if (!same) newText = t("free");
}
if (newText !== false) {
room.$.currentEvent.text(newText);
}
if (newTime !== false) {
- room.$.currentRemain.text(newTime);
+ room.$.currentRemain.text(t("for") + " " +newTime);
}
if (room.lastFreeSeats !== seats || !same) {
SetFreeSeats(room);
diff --git a/modules-available/locationinfo/templates/frontend-summary.html b/modules-available/locationinfo/templates/frontend-summary.html
index 95299e63..ae089da5 100644
--- a/modules-available/locationinfo/templates/frontend-summary.html
+++ b/modules-available/locationinfo/templates/frontend-summary.html
@@ -63,7 +63,7 @@
}
.pc-idle, .pc-occupied, .pc-offline, .pc-broken, .pc-standby {
- padding: 2px 1px;
+ padding: 2px 0px;
text-align: center;
font-size: 90%;
font-weight: 800;
@@ -604,7 +604,11 @@
// TODO: Add seconds again with a better update rate.
var time_split = time.split(":");
if (time != "") {
- $("#div_Time_" + id).text(time_split[0] + ":" + time_split[1]);
+ if (time_split[0] > 0) {
+ $("#div_Time_" + id).text(t("for") + " " + time_split[0] + "h " + time_split[1]+"min");
+ } else {
+ $("#div_Time_" + id).text(t("for") + " " + time_split[1]+"min");
+ }
} else {
$("#div_Time_" + id).text(time);
}
@@ -759,6 +763,7 @@
<span data-tag="room">{{lang_room}}</span>
<span data-tag="closed">{{lang_closed}}</span>
<span data-tag="free">{{lang_free}}</span>
+ <span data-tag="for">{{lang_for}}</span>
<span data-tag="shortSun">{{lang_shortSun}}</span>
<span data-tag="shortMon">{{lang_shortMon}}</span>
<span data-tag="shortTue">{{lang_shortTue}}</span>
diff --git a/modules-available/statistics/api.inc.php b/modules-available/statistics/api.inc.php
index 674cc48d..280e5abc 100644
--- a/modules-available/statistics/api.inc.php
+++ b/modules-available/statistics/api.inc.php
@@ -34,7 +34,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 FROM machine WHERE machineuuid = :uuid', array('uuid' => $uuid));
+ $old = Database::queryFirst('SELECT clientip, 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');
settype($old['lastseen'], 'integer');
@@ -114,6 +115,7 @@ if ($type{0} === '~') {
. ' cpumodel = :cpumodel,'
. ' systemmodel = :systemmodel,'
. ' id44mb = :id44mb,'
+ . ' live_tmpsize = 0, live_swapsize = 0, live_memsize = 0,'
. ' badsectors = :badsectors,'
. ' data = :data,'
. ' state = :state '
@@ -123,32 +125,20 @@ if ($type{0} === '~') {
}
}
// Maybe log old crashed session
- if ($uptime < 120) {
+ if ($uptime < 150 && $old !== false) {
// See if we have a lingering session, create statistic entry if so
- if ($old !== false && $old['logintime'] !== 0) {
+ if ($old['state'] === 'OCCUPIED' && $old['logintime'] !== 0) {
$sessionLength = $old['lastseen'] - $old['logintime'];
if ($sessionLength > 30 && $sessionLength < 86400*2) {
- Database::exec('INSERT INTO statistic (dateline, typeid, machineuuid, clientip, username, data)'
- . " VALUES (:start, '~session-length', :uuid, :clientip, '', :length)", array(
- 'start' => $old['logintime'],
- 'uuid' => $uuid,
- 'clientip' => $ip,
- 'length' => $sessionLength
- ));
+ Statistics::logMachineState($uuid, $ip, Statistics::SESSION_LENGTH, $old['logintime'], $sessionLength);
}
}
// Write poweroff period length to statistic table
- if ($old !== false && $old['lastseen'] !== 0) {
+ if ($old['lastseen'] !== 0) {
$lastSeen = $old['lastseen'];
$offtime = ($NOW - $uptime) - $lastSeen;
- if ($offtime > 300 && $offtime < 86400 * 90) {
- Database::exec('INSERT INTO statistic (dateline, typeid, machineuuid, clientip, username, data)'
- . " VALUES (:shutdown, '~offline-length', :uuid, :clientip, '', :length)", array(
- 'shutdown' => $lastSeen,
- 'uuid' => $uuid,
- 'clientip' => $ip,
- 'length' => $offtime
- ));
+ if ($offtime > 90 && $offtime < 86400 * 30) {
+ Statistics::logMachineState($uuid, $ip, $old['state'] === 'STANDBY' ? Statistics::SUSPEND_LENGTH : Statistics::OFFLINE_LENGTH, $lastSeen, $offtime);
}
}
}
@@ -164,7 +154,10 @@ if ($type{0} === '~') {
// Log potential crash
if ($old['state'] === 'IDLE' || $old['state'] === 'OCCUPIED') {
- writeClientLog('machine-mismatch-poweron', 'Client sent poweron event, but previous known state is ' . $old['state']);
+ writeClientLog('machine-mismatch-poweron', 'Poweron event, but previous known state is ' . $old['state']
+ . '. RAM: ' . Util::readableFileSize($old['live_memfree'], -1, 2)
+ . ', Swap: ' . Util::readableFileSize($old['live_swapfree'], -1, 2)
+ . ', ID44: ' . Util::readableFileSize($old['live_tmpfree'], -1, 2));
}
}
@@ -173,36 +166,45 @@ if ($type{0} === '~') {
} else if ($type === '~runstate') {
// Usage (occupied/free)
$sessionLength = 0;
+ $strUpdateBoottime = '';
if ($old === false) die("Unknown machine.\n");
if ($old['clientip'] !== $ip) {
EventLog::warning("[runstate] IP address of client $uuid seems to have changed ({$old['clientip']} -> $ip)");
die("Address changed.\n");
}
$used = Request::post('used', 0, 'integer');
- if ($old['state'] === 'OFFLINE' && $NOW - $old['lastseen'] > 600) {
- $strUpdateBoottime = ' lastboot = UNIX_TIMESTAMP(), ';
- } else {
- $strUpdateBoottime = '';
- }
- // 1) Log last session length if we didn't see the machine for a while
- if ($NOW - $old['lastseen'] > 610 && $old['lastseen'] !== 0) {
- // Old session timed out - might be caused by hard reboot
- if ($old['logintime'] !== 0) {
- if ($old['lastseen'] > $old['logintime']) {
- $sessionLength = $old['lastseen'] - $old['logintime'];
- }
- $old['logintime'] = 0;
- }
- }
- // Figure out what's happening - state changes
$params = array(
'uuid' => $uuid,
'oldlastseen' => $old['lastseen'],
'oldstate' => $old['state'],
);
+ 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
+ // caused our cron.inc.php to time out the client and reset it to OFFLINE
+ if ($NOW - $old['lastseen'] > 900) {
+ $strUpdateBoottime = ' lastboot = UNIX_TIMESTAMP(), ';
+ }
+ // 1) Log last session length if we didn't see the machine for a while
+ if ($NOW - $old['lastseen'] > 900 && $old['lastseen'] !== 0) {
+ // Old session timed out - might be caused by hard reboot
+ if ($old['logintime'] !== 0) {
+ if ($old['lastseen'] > $old['logintime']) {
+ $sessionLength = $old['lastseen'] - $old['logintime'];
+ }
+ }
+ }
+ }
+ foreach (['memsize', 'tmpsize', 'swapsize', 'memfree', 'tmpfree', 'swapfree'] as $item) {
+ $strUpdateBoottime .= ' live_' . $item . ' = :_' . $item . ', ';
+ $params['_' . $item] = ceil(Request::post($item, 0, 'int') / 1024);
+ }
+ // Figure out what's happening - state changes
if ($used === 0 && $old['state'] !== 'IDLE') {
- // Is not in use, was in use before
- $sessionLength = $NOW - $old['logintime'];
+ if ($old['state'] === 'OCCUPIED' && $sessionLength === 0) {
+ // Is not in use, was in use before
+ $sessionLength = $NOW - $old['logintime'];
+ }
$res = Database::exec('UPDATE machine SET lastseen = UNIX_TIMESTAMP(),'
. $strUpdateBoottime
. " logintime = 0, currentuser = NULL, state = 'IDLE' "
@@ -232,13 +234,7 @@ if ($type{0} === '~') {
}
// 9) Log last session length if applicable
if ($mode === false && $sessionLength > 0 && $sessionLength < 86400*2 && $old['logintime'] !== 0) {
- Database::exec('INSERT INTO statistic (dateline, typeid, machineuuid, clientip, username, data)'
- . " VALUES (:start, '~session-length', :uuid, :clientip, '', :length)", array(
- 'start' => $old['logintime'],
- 'uuid' => $uuid,
- 'clientip' => $ip,
- 'length' => $sessionLength
- ));
+ Statistics::logMachineState($uuid, $ip, Statistics::SESSION_LENGTH, $old['logintime'], $sessionLength);
}
} elseif ($type === '~poweroff') {
if ($old === false) die("Unknown machine.\n");
@@ -246,16 +242,10 @@ if ($type{0} === '~') {
EventLog::warning("[poweroff] IP address of client $uuid seems to have changed ({$old['clientip']} -> $ip)");
die("Address changed.\n");
}
- if ($mode === false && $old['logintime'] !== 0) {
+ if ($mode === false && $old['state'] === 'OCCUPIED' && $old['logintime'] !== 0) {
$sessionLength = $old['lastseen'] - $old['logintime'];
if ($sessionLength > 0 && $sessionLength < 86400*2) {
- Database::exec('INSERT INTO statistic (dateline, typeid, machineuuid, clientip, username, data)'
- . " VALUES (:start, '~session-length', :uuid, :clientip, '', :length)", array(
- 'start' => $old['logintime'],
- 'uuid' => $uuid,
- 'clientip' => $ip,
- 'length' => $sessionLength
- ));
+ Statistics::logMachineState($uuid, $ip, Statistics::SESSION_LENGTH, $old['logintime'], $sessionLength);
}
}
Database::exec("UPDATE machine SET logintime = 0, lastseen = UNIX_TIMESTAMP(), state = 'OFFLINE'
@@ -368,13 +358,7 @@ if ($type{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
- ));
+ Statistics::logMachineState($uuid, $ip, Statistics::SUSPEND_LENGTH, $lastSeen, $duration);
}
}
} else {
@@ -449,9 +433,14 @@ if ($type{0} === '.') {
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;
+ if ($new['mbram'] < 6200) {
+ $ram1 = ceil($old['mbram'] / 512) / 2;
+ $ram2 = ceil($new['mbram'] / 512) / 2;
+ } else {
+ $ram1 = ceil($old['mbram'] / 1024);
+ $ram2 = ceil($new['mbram'] / 1024);
+ }
+ if ($ram1 !== $ram2) {
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']) {
diff --git a/modules-available/statistics/hooks/cron.inc.php b/modules-available/statistics/hooks/cron.inc.php
index f05762bc..6393b2c6 100644
--- a/modules-available/statistics/hooks/cron.inc.php
+++ b/modules-available/statistics/hooks/cron.inc.php
@@ -21,22 +21,37 @@ function logstats()
function state_cleanup()
{
// Fix online state of machines that crashed
- $standby = time() - 86400 * 2; // Reset standby machines after two days
+ $standby = time() - 86400 * 4; // Reset standby machines after four days
$on = time() - 610; // Reset others after ~10 minutes
// Query for logging
- $res = Database::simpleQuery("SELECT machineuuid, clientip, state FROM machine WHERE lastseen < If(state = 'STANDBY', $standby, $on) AND state <> 'OFFLINE'");
+ $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'");
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
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'],
+ 'description' => 'Client timed out, last known state is ' . $row['state']
+ . '. RAM: ' . Util::readableFileSize($row['live_memfree'], -1, 2)
+ . ', Swap: ' . Util::readableFileSize($row['live_swapfree'], -1, 2)
+ . ', ID44: ' . Util::readableFileSize($row['live_tmpfree'], -1, 2),
'longdesc' => '',
'uuid' => $row['machineuuid'],
));
+ if ($row['state'] === 'OCCUPIED') {
+ $length = $row['lastseen'] - $row['logintime'];
+ if ($length > 0 && $length < 86400 * 7) {
+ Statistics::logMachineState($row['machineuuid'], $row['clientip'], Statistics::SESSION_LENGTH, $row['logintime'], $length);
+ }
+ } elseif ($row['state'] === 'STANDBY') {
+ $length = time() - $row['lastseen'];
+ if ($length > 0 && $length < 86400 * 7) {
+ Statistics::logMachineState($row['machineuuid'], $row['clientip'], Statistics::SUSPEND_LENGTH, $row['lastseen'], $length);
+ }
+ }
}
- // Update -- yes this is not atomic. Should be sufficient for simple warnings though.
- Database::exec("UPDATE machine SET state = 'OFFLINE' WHERE lastseen < If(state = 'STANDBY', $standby, $on) AND state <> 'OFFLINE'");
+ // Update -- yes this is not atomic. Should be sufficient for simple warnings and bookkeeping though.
+ Database::exec("UPDATE machine SET logintime = 0, state = 'OFFLINE' WHERE lastseen < If(state = 'STANDBY', $standby, $on) AND state <> 'OFFLINE'");
}
state_cleanup();
diff --git a/modules-available/statistics/inc/filter.inc.php b/modules-available/statistics/inc/filter.inc.php
index 3ccea2c3..46de467b 100644
--- a/modules-available/statistics/inc/filter.inc.php
+++ b/modules-available/statistics/inc/filter.inc.php
@@ -14,6 +14,13 @@ class Filter
public $operator;
public $argument;
+ private static $keyCounter = 0;
+
+ public static function getNewKey($colname)
+ {
+ return $colname . '_' . (self::$keyCounter++);
+ }
+
public function __construct($column, $operator, $argument = null)
{
$this->column = trim($column);
@@ -24,8 +31,7 @@ class Filter
/* returns a where clause and adds needed operators to the passed array */
public function whereClause(&$args, &$joins)
{
- global $unique_key;
- $key = $this->column . '_arg' . ($unique_key++);
+ $key = Filter::getNewKey($this->column);
$addendum = '';
/* check if we have to do some parsing*/
@@ -226,8 +232,7 @@ class StateFilter extends Filter
$map = [ 'on' => ['IDLE', 'OCCUPIED'], 'off' => ['OFFLINE'], 'idle' => ['IDLE'], 'occupied' => ['OCCUPIED'], 'standby' => ['STANDBY'] ];
$neg = $this->operator == '!=' ? 'NOT ' : '';
if (array_key_exists($this->argument, $map)) {
- global $unique_key;
- $key = $this->column . '_arg' . ($unique_key++);
+ $key = Filter::getNewKey($this->column);
$args[$key] = $map[$this->argument];
return " machine.state $neg IN ( :$key ) ";
} else {
@@ -259,8 +264,7 @@ class LocationFilter extends Filter
if ($this->argument === 0) {
return "machine.locationid IS $neg NULL";
} else {
- global $unique_key;
- $key = $this->column . '_arg' . ($unique_key++);
+ $key = Filter::getNewKey($this->column);
if ($recursive) {
$args[$key] = array_keys(Location::getRecursiveFlat($this->argument));
} else {
diff --git a/modules-available/statistics/inc/parser.inc.php b/modules-available/statistics/inc/parser.inc.php
index b179b4a3..0d39079d 100644
--- a/modules-available/statistics/inc/parser.inc.php
+++ b/modules-available/statistics/inc/parser.inc.php
@@ -104,10 +104,12 @@ class Parser {
foreach ($lines as $line) {
if (preg_match('/^Disk (\S+):.* (\d+) bytes/i', $line, $out)) {
// --- Beginning of MBR disk ---
+ unset($hdd);
if ($out[2] < 10000) // sometimes vmware reports lots of 512byte disks
continue;
+ if (substr($out[1], 0, 8) === '/dev/dm-') // Ignore device mapper
+ continue;
// disk total size and name
- unset($hdd);
$mbrToMbFactor = 0; // This is != 0 for mbr
$sectorToMbFactor = 0; // This is != for gpt
$hdd = array(
@@ -122,10 +124,12 @@ class Parser {
$hdds[] = &$hdd;
} elseif (preg_match('/^Disk (\S+):\s+(\d+)\s+sectors,/i', $line, $out)) {
// --- Beginning of GPT disk ---
+ unset($hdd);
if ($out[2] < 1000) // sometimes vmware reports lots of 512byte disks
continue;
+ if (substr($out[1], 0, 8) === '/dev/dm-') // Ignore device mapper
+ continue;
// disk total size and name
- unset($hdd);
$mbrToMbFactor = 0; // This is != 0 for mbr
$sectorToMbFactor = 0; // This is != for gpt
$hdd = array(
@@ -213,7 +217,7 @@ class Parser {
$hdd['size'] = round(($hdd['sectors'] * $sectorToMbFactor) / 1024);
}
$free = $hdd['size'] - $hdd['used'];
- if ($free > 5 || ($free / $hdd['size']) > 0.1) {
+ if ($hdd['size'] > 0 && ($free > 5 || ($free / $hdd['size']) > 0.1)) {
$hdd['partitions'][] = array(
'id' => 'free-id-' . $i,
'name' => Dictionary::translate('unused'),
diff --git a/modules-available/statistics/inc/statistics.inc.php b/modules-available/statistics/inc/statistics.inc.php
index 2500f16f..1f8a081a 100644
--- a/modules-available/statistics/inc/statistics.inc.php
+++ b/modules-available/statistics/inc/statistics.inc.php
@@ -70,4 +70,21 @@ class Statistics
return $list;
}
+ const SESSION_LENGTH = '~session-length';
+ const OFFLINE_LENGTH = '~offline-length';
+ const SUSPEND_LENGTH = '~suspend-length';
+
+ public static function logMachineState($uuid, $ip, $type, $start, $length, $username = '')
+ {
+ return Database::exec('INSERT INTO statistic (dateline, typeid, machineuuid, clientip, username, data)'
+ . " VALUES (:start, :type, :uuid, :clientip, :username, :length)", array(
+ 'start' => $start,
+ 'type' => $type,
+ 'uuid' => $uuid,
+ 'clientip' => $ip,
+ 'username' => $username,
+ 'length' => $length,
+ ));
+ }
+
}
diff --git a/modules-available/statistics/install.inc.php b/modules-available/statistics/install.inc.php
index 4e2dfcca..84e038a4 100644
--- a/modules-available/statistics/install.inc.php
+++ b/modules-available/statistics/install.inc.php
@@ -234,5 +234,22 @@ if (!tableHasColumn('machine', 'state')) {
$res[] = UPDATE_DONE;
}
+// 2019-01-25: Add memory/temp stats column
+if (!tableHasColumn('machine', 'live_tmpsize')) {
+ $ret = Database::exec("ALTER TABLE `machine`
+ ADD COLUMN `live_tmpsize` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `id44mb`,
+ ADD COLUMN `live_tmpfree` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `live_tmpsize`,
+ ADD COLUMN `live_swapsize` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `live_tmpfree`,
+ ADD COLUMN `live_swapfree` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `live_swapsize`,
+ ADD COLUMN `live_memsize` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `live_swapfree`,
+ ADD COLUMN `live_memfree` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `live_memsize`,
+ ADD INDEX `live_tmpfree` (`live_tmpfree`),
+ ADD INDEX `live_memfree` (`live_memfree`)");
+ if ($ret === false) {
+ finalResponse(UPDATE_FAILED, 'Adding state column to machine table failed: ' . Database::lastError());
+ }
+ $res[] = UPDATE_DONE;
+}
+
// Create response
responseFromArray($res);
diff --git a/modules-available/statistics/lang/de/template-tags.json b/modules-available/statistics/lang/de/template-tags.json
index 84c4690c..2567eea1 100644
--- a/modules-available/statistics/lang/de/template-tags.json
+++ b/modules-available/statistics/lang/de/template-tags.json
@@ -14,6 +14,7 @@
"lang_event": "Ereignis",
"lang_eventType": "Typ",
"lang_firstSeen": "Erste Aktivit\u00e4t",
+ "lang_free": "frei",
"lang_gbRam": "RAM",
"lang_hardwareSummary": "Hardware",
"lang_hdds": "Festplatten",
@@ -40,6 +41,7 @@
"lang_machineStandby": "Im Standby",
"lang_machineSummary": "Zusammenfassung",
"lang_maximumAbbrev": "Max.",
+ "lang_memFree": "RAM frei (MB)",
"lang_memoryStats": "Arbeitsspeicher",
"lang_model": "Modell",
"lang_modelCount": "Anzahl",
@@ -82,10 +84,12 @@
"lang_subnet": "Subnetz",
"lang_sureDeletePermanent": "M\u00f6chten Sie diese(n) Rechner wirklich unwiderruflich aus der Datenbank entfernen?\r\n\r\nWichtig: L\u00f6schen verhindert nicht, dass ein Rechner nach erneutem Starten von bwLehrpool wieder in die Datenbank aufgenommen wird.",
"lang_sureReplaceNoUndo": "Wollen Sie die Daten ausgew\u00e4hlten Rechner \u00fcbertragen? Diese Aktion kann nicht r\u00fcckg\u00e4ngig gemacht werden.",
+ "lang_swapFree": "swap frei (MB)",
"lang_tempPart": "Temp. Partition",
"lang_tempPartStats": "Tempor\u00e4re Partition",
"lang_thoseAreProjectors": "Diese Modellnamen werden als Beamer behandelt, auch wenn die EDID-Informationen des Ger\u00e4tes anderes berichten.",
"lang_timebarDesc": "Visuelle Darstellung der letzten Tage. Rote Abschnitte zeigen, wann der Rechner belegt war, gr\u00fcne, wann er nicht verwendet wurde, aber eingeschaltet war. Die leicht abgedunkelten Abschnitte markieren N\u00e4chte (22 bis 8 Uhr).",
+ "lang_tmpFree": "ID44 frei (MB)",
"lang_tmpGb": "Temp-HDD",
"lang_total": "Gesamt",
"lang_usageDetails": "Nutzungsdetails",
diff --git a/modules-available/statistics/lang/en/template-tags.json b/modules-available/statistics/lang/en/template-tags.json
index b064ee50..1d9cd4da 100644
--- a/modules-available/statistics/lang/en/template-tags.json
+++ b/modules-available/statistics/lang/en/template-tags.json
@@ -14,6 +14,7 @@
"lang_event": "Event",
"lang_eventType": "Type",
"lang_firstSeen": "First seen",
+ "lang_free": "free",
"lang_gbRam": "RAM",
"lang_hardwareSummary": "Hardware",
"lang_hdds": "Hard disk drives",
@@ -40,6 +41,7 @@
"lang_machineStandby": "In standby mode",
"lang_machineSummary": "Summary",
"lang_maximumAbbrev": "max.",
+ "lang_memFree": "RAM free (MB)",
"lang_memoryStats": "Memory",
"lang_model": "Model",
"lang_modelCount": "Count",
@@ -82,10 +84,12 @@
"lang_subnet": "Subnet",
"lang_sureDeletePermanent": "Are your sure you want to delete the selected machine(s) from the database? This cannot be undone.\r\n\r\nNote: Deleting machines from the database does not prevent booting up bwLehrpool again, which would recreate their respective database entries.",
"lang_sureReplaceNoUndo": "Are you sure you want to replace the selected machine pairs? This action cannot be undone.",
+ "lang_swapFree": "swap free (MB)",
"lang_tempPart": "Temp. partition",
"lang_tempPartStats": "Temporary partition",
"lang_thoseAreProjectors": "These model names will always be treated as beamers, even if the device's EDID data says otherwise.",
"lang_timebarDesc": "Visual representation of the last few days. Red parts mark periods where the client was occupied, green parts where the client was idle. Dimmed parts mark nights (10pm to 8am).",
+ "lang_tmpFree": "ID44 free (MB)",
"lang_tmpGb": "Temp HDD",
"lang_total": "Total",
"lang_usageDetails": "Detailed usage",
diff --git a/modules-available/statistics/page.inc.php b/modules-available/statistics/page.inc.php
index abacc8d2..a9cde6fb 100644
--- a/modules-available/statistics/page.inc.php
+++ b/modules-available/statistics/page.inc.php
@@ -1,7 +1,6 @@
<?php
global $STATS_COLORS, $SIZE_ID44, $SIZE_RAM;
-global $unique_key;
$STATS_COLORS = array();
for ($i = 0; $i < 10; ++$i) {
@@ -14,9 +13,9 @@ $SIZE_RAM = array(1, 2, 3, 4, 6, 8, 10, 12, 16, 24, 32, 48, 64, 96, 128, 192, 25
class Page_Statistics extends Page
{
/* some constants, TODO: Find a better place */
- public static $op_nominal;
- public static $op_ordinal;
- public static $op_stringcmp;
+ const OP_NOMINAL = ['!=', '='];
+ const OP_ORDINAL = ['!=', '<=', '>=', '=', '<', '>'];
+ const OP_STRCMP = ['!~', '~', '=', '!='];
public static $columns;
private $query;
@@ -27,123 +26,130 @@ class Page_Statistics extends Page
*/
private $haveSubpage;
- /* PHP sucks, no static, const array definitions... Or am I missing something? */
- public function initConstants()
+ /**
+ * Do this here instead of const since we need to check for available modules while building array.
+ */
+ public static function initConstants()
{
- Page_Statistics::$op_nominal = ['!=', '='];
- Page_Statistics::$op_ordinal = ['!=', '<=', '>=', '=', '<', '>'];
- Page_Statistics::$op_stringcmp = ['!~', '~', '=', '!='];
Page_Statistics::$columns = [
'machineuuid' => [
- 'op' => Page_Statistics::$op_nominal,
+ 'op' => Page_Statistics::OP_NOMINAL,
'type' => 'string',
'column' => true,
],
'macaddr' => [
- 'op' => Page_Statistics::$op_nominal,
+ 'op' => Page_Statistics::OP_NOMINAL,
'type' => 'string',
'column' => true,
],
'firstseen' => [
- 'op' => Page_Statistics::$op_ordinal,
+ 'op' => Page_Statistics::OP_ORDINAL,
'type' => 'date',
'column' => true,
],
'lastseen' => [
- 'op' => Page_Statistics::$op_ordinal,
+ 'op' => Page_Statistics::OP_ORDINAL,
'type' => 'date',
'column' => true,
],
'logintime' => [
- 'op' => Page_Statistics::$op_ordinal,
+ 'op' => Page_Statistics::OP_ORDINAL,
'type' => 'date',
'column' => true,
],
'realcores' => [
- 'op' => Page_Statistics::$op_ordinal,
+ 'op' => Page_Statistics::OP_ORDINAL,
'type' => 'int',
'column' => true,
],
'systemmodel' => [
- 'op' => Page_Statistics::$op_stringcmp,
+ 'op' => Page_Statistics::OP_STRCMP,
'type' => 'string',
'column' => true,
],
'cpumodel' => [
- 'op' => Page_Statistics::$op_stringcmp,
+ 'op' => Page_Statistics::OP_STRCMP,
'type' => 'string',
'column' => true,
],
'hddgb' => [
- 'op' => Page_Statistics::$op_ordinal,
+ 'op' => Page_Statistics::OP_ORDINAL,
'type' => 'int',
'column' => false,
'map_sort' => 'id44mb'
],
'gbram' => [
- 'op' => Page_Statistics::$op_ordinal,
+ 'op' => Page_Statistics::OP_ORDINAL,
'type' => 'int',
'map_sort' => 'mbram',
'column' => false,
],
'kvmstate' => [
- 'op' => Page_Statistics::$op_nominal,
+ 'op' => Page_Statistics::OP_NOMINAL,
'type' => 'enum',
'column' => true,
'values' => ['ENABLED', 'DISABLED', 'UNSUPPORTED']
],
'badsectors' => [
- 'op' => Page_Statistics::$op_ordinal,
+ 'op' => Page_Statistics::OP_ORDINAL,
'type' => 'int',
'column' => true
],
'clientip' => [
- 'op' => Page_Statistics::$op_nominal,
+ 'op' => Page_Statistics::OP_NOMINAL,
'type' => 'string',
'column' => true
],
'hostname' => [
- 'op' => Page_Statistics::$op_stringcmp,
+ 'op' => Page_Statistics::OP_STRCMP,
'type' => 'string',
'column' => true
],
'subnet' => [
- 'op' => Page_Statistics::$op_nominal,
+ 'op' => Page_Statistics::OP_NOMINAL,
'type' => 'string',
'column' => false
],
'currentuser' => [
- 'op' => Page_Statistics::$op_nominal,
+ 'op' => Page_Statistics::OP_NOMINAL,
'type' => 'string',
'column' => true
],
'state' => [
- 'op' => Page_Statistics::$op_nominal,
+ 'op' => Page_Statistics::OP_NOMINAL,
'type' => 'enum',
'column' => true,
'values' => ['occupied', 'on', 'off', 'idle', 'standby']
],
- 'runtime' => [
- 'op' => Page_Statistics::$op_ordinal,
+ 'live_swapfree' => [
+ 'op' => Page_Statistics::OP_ORDINAL,
+ 'type' => 'int',
+ 'column' => true
+ ],
+ 'live_memfree' => [
+ 'op' => Page_Statistics::OP_ORDINAL,
+ 'type' => 'int',
+ 'column' => true
+ ],
+ 'live_tmpfree' => [
+ 'op' => Page_Statistics::OP_ORDINAL,
'type' => 'int',
'column' => true
],
];
if (Module::isAvailable('locations')) {
Page_Statistics::$columns['location'] = [
- 'op' => Page_Statistics::$op_stringcmp,
+ 'op' => Page_Statistics::OP_STRCMP,
'type' => 'enum',
'column' => false,
'values' => array_keys(Location::getLocationsAssoc()),
];
}
- /* TODO ... */
}
protected function doPreprocess()
{
- $this->initConstants();
User::load();
if (!User::isLoggedIn()) {
Message::addError('main.no-permission');
@@ -768,9 +774,9 @@ class Page_Statistics extends Page
$row['currentsession'] = $lecture['displayname'];
$row['lectureid'] = $lecture['lectureid'];
}
+ $row['session'] = $row['currentsession'];
+ return;
}
- $row['session'] = $row['currentsession'];
- return;
}
$res = Database::simpleQuery('SELECT dateline, username, data FROM statistic'
. " WHERE clientip = :ip AND typeid = '.vmchooser-session-name'"
@@ -787,14 +793,17 @@ class Page_Statistics extends Page
}
if ($session !== false) {
$row['session'] = $session['data'];
- $row['username'] = $session['username'];
+ if (empty($row['currentuser'])) {
+ $row['username'] = $session['username'];
+ }
}
}
private function showMachine($uuid)
{
- $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',
+ $client = Database::queryFirst('SELECT machineuuid, locationid, macaddr, clientip, firstseen, lastseen, logintime, lastboot, state,
+ mbram, live_tmpsize, live_tmpfree, live_swapsize, live_swapfree, live_memsize, live_memfree,
+ kvmstate, cpumodel, id44mb, data, hostname, currentuser, currentsession, notes FROM machine WHERE machineuuid = :uuid',
array('uuid' => $uuid));
if ($client === false) {
Message::addError('unknown-machine', $uuid);
@@ -830,6 +839,7 @@ class Page_Statistics extends Page
$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']);
+ $client['logintime_s'] = date('d.m.Y H:i', $client['logintime']);
if ($client['lastboot'] == 0) {
$client['lastboot_s'] = '-';
} else {
@@ -839,9 +849,14 @@ class Page_Statistics extends Page
$client['lastboot_s'] .= ' (Up ' . floor($uptime / 86400) . 'd ' . gmdate('H:i', $uptime) . ')';
}
}
- $client['logintime_s'] = date('d.m.Y H:i', $client['logintime']);
- $client['gbram'] = round(round($client['mbram'] / 500) / 2, 1);
+ $client['gbram'] = round(ceil($client['mbram'] / 512) / 2, 1);
$client['gbtmp'] = round($client['id44mb'] / 1024);
+ foreach (['tmp', 'swap', 'mem'] as $item) {
+ if ($client['live_' . $item . 'size'] == 0)
+ continue;
+ $client['live_' . $item . 'percent'] = round(($client['live_' . $item . 'free'] / $client['live_' . $item . 'size']) * 100, 2);
+ $client['live_' . $item . 'free_s'] = Util::readableFileSize($client['live_' . $item . 'free'], -1, 2);
+ }
$client['ramclass'] = $this->ramColorClass($client['mbram']);
$client['kvmclass'] = $this->kvmColorClass($client['kvmstate']);
$client['hddclass'] = $this->hddColorClass($client['gbtmp']);
@@ -910,16 +925,18 @@ class Page_Statistics extends Page
//if ($cutoff < $client['firstseen']) $cutoff = $client['firstseen'];
$scale = 100 / ($NOW - $cutoff);
$res = Database::simpleQuery('SELECT dateline, typeid, data FROM statistic'
- . " WHERE dateline > :cutoff AND typeid IN ('~session-length', '~offline-length') AND machineuuid = :uuid ORDER BY dateline ASC", array(
+ . " WHERE dateline > :cutoff AND typeid IN (:sessionLength, :offlineLength) AND machineuuid = :uuid ORDER BY dateline ASC", array(
'cutoff' => $cutoff - 86400 * 14,
'uuid' => $uuid,
+ 'sessionLength' => Statistics::SESSION_LENGTH,
+ 'offlineLength' => Statistics::OFFLINE_LENGTH,
));
$spans['rows'] = array();
$spans['graph'] = '';
$last = false;
$first = true;
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- if (!$client['isclient'] && $row['typeid'] === '~session-length')
+ if (!$client['isclient'] && $row['typeid'] === Statistics::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
@@ -945,9 +962,12 @@ class Page_Statistics extends Page
}
$row['from'] = Util::prettyTime($row['dateline']);
$row['duration'] = floor($row['data'] / 86400) . 'd ' . gmdate('H:i', $row['data']);
- if ($row['typeid'] === '~offline-length') {
+ if ($row['typeid'] === Statistics::OFFLINE_LENGTH) {
$row['glyph'] = 'off';
$color = '#444';
+ } elseif ($row['typeid'] === Statistics::SUSPEND_LENGTH) {
+ $row['glyph'] = 'pause';
+ $color = '#686';
} else {
$row['glyph'] = 'user';
$color = '#e77';
@@ -967,8 +987,26 @@ class Page_Statistics extends Page
}
if ($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>';
+ $spans['rows'][] = [
+ 'from' => Util::prettyTime($client['logintime']),
+ 'duration' => '-',
+ 'glyph' => 'user',
+ ];
+ $row['duration'] = floor($row['data'] / 86400) . 'd ' . gmdate('H:i', $row['data']);
} elseif ($client['state'] === 'OFFLINE') {
$spans['graph'] .= '<div style="background:#444;left:' . round(($client['lastseen'] - $cutoff) * $scale, 2) . '%;width:' . round(($NOW - $client['lastseen'] + 900) * $scale, 2) . '%">&nbsp;</div>';
+ $spans['rows'][] = [
+ 'from' => Util::prettyTime($client['lastseen']),
+ 'duration' => '-',
+ 'glyph' => 'off',
+ ];
+ } elseif ($client['state'] === 'STANDBY') {
+ $spans['graph'] .= '<div style="background:#686;left:' . round(($client['lastseen'] - $cutoff) * $scale, 2) . '%;width:' . round(($NOW - $client['lastseen'] + 900) * $scale, 2) . '%">&nbsp;</div>';
+ $spans['rows'][] = [
+ 'from' => Util::prettyTime($client['lastseen']),
+ 'duration' => '-',
+ 'glyph' => 'pause',
+ ];
}
$t = explode('-', date('Y-n-j-G', $cutoff));
if ($t[3] >= 8 && $t[3] <= 22) {
@@ -1104,3 +1142,5 @@ class Page_Statistics extends Page
), true);
}
}
+
+Page_Statistics::initConstants();
diff --git a/modules-available/statistics/style.css b/modules-available/statistics/style.css
index 1496ac87..c48275ba 100644
--- a/modules-available/statistics/style.css
+++ b/modules-available/statistics/style.css
@@ -8,4 +8,36 @@
border-radius: 25px;
font-size: 20px;
line-height: 40px;
+}
+
+.meter {
+ position: relative;
+ border-radius: 5px;
+ border: 1px solid #999;
+ background: linear-gradient(to right, #9e6 0%, #fb8 66%, #f32 100%);
+ height: 1.25em;
+ padding: 0;
+ width: 100%;
+ overflow: hidden;
+}
+
+.meter .bar {
+ position: absolute;
+ top: 0;
+ height: 100%;
+ right: 0;
+ background: #efe;
+ display: inline-block;
+ padding: 0;
+ margin: 0 0 0 auto;
+}
+
+.meter .text {
+ position: absolute;
+ right: 5px;
+ overflow: visible;
+ font-size: 8pt;
+ white-space: nowrap;
+ z-index: 1000;
+ text-shadow: #fff 1px 1px;
} \ No newline at end of file
diff --git a/modules-available/statistics/templates/filterbox.html b/modules-available/statistics/templates/filterbox.html
index cd8ec24d..07aa7320 100644
--- a/modules-available/statistics/templates/filterbox.html
+++ b/modules-available/statistics/templates/filterbox.html
@@ -101,7 +101,10 @@ var slxFilterNames = {
currentuser: '{{lang_currentUser}}',
subnet: '{{lang_subnet}}',
runtime: '{{lang_runtimeHours}}',
- hostname: '{{lang_hostname}}'
+ hostname: '{{lang_hostname}}',
+ live_swapfree: '{{lang_swapFree}}',
+ live_memfree: '{{lang_memFree}}',
+ live_tmpfree: '{{lang_tmpFree}}'
};
slxLocations = {{{locations}}};
diff --git a/modules-available/statistics/templates/machine-main.html b/modules-available/statistics/templates/machine-main.html
index f1021482..44f03a99 100644
--- a/modules-available/statistics/templates/machine-main.html
+++ b/modules-available/statistics/templates/machine-main.html
@@ -117,9 +117,23 @@
<tr class="{{ramclass}}">
<td class="text-nowrap">{{lang_ram}}</td>
<td>
- {{gbram}}&thinsp;GiB
- {{#maxram}}({{lang_maximumAbbrev}} {{maxram}}){{/maxram}}
- {{ramtype}}
+ <div>
+ {{gbram}}&thinsp;GiB
+ {{#maxram}}({{lang_maximumAbbrev}} {{maxram}}){{/maxram}}
+ {{ramtype}}
+ </div>
+ {{#live_memsize}}
+ <div class="meter">
+ <div class="text">{{live_memfree_s}} {{lang_free}}</div>
+ <div class="bar" style="width:{{live_mempercent}}%"></div>
+ </div>
+ {{/live_memsize}}
+ {{#live_swapsize}}
+ <div class="meter">
+ <div class="text">{{live_swapfree_s}} {{lang_free}}</div>
+ <div class="bar" style="width:{{live_swappercent}}%"></div>
+ </div>
+ {{/live_swapsize}}
</td>
</tr>
{{#extram}}
@@ -135,7 +149,17 @@
{{/extram}}
<tr class="{{hddclass}}">
<td class="text-nowrap">{{lang_tempPart}}</td>
- <td>{{gbtmp}}&thinsp;GiB</td>
+ <td>
+ <div>
+ {{gbtmp}}&thinsp;GiB
+ </div>
+ {{#live_tmpsize}}
+ <div class="meter">
+ <div class="text">{{live_tmpfree_s}} {{lang_free}}</div>
+ <div class="bar" style="width:{{live_tmppercent}}%"></div>
+ </div>
+ {{/live_tmpsize}}
+ </td>
</tr>
<tr class="{{kvmclass}}">
<td class="text-nowrap">{{lang_64bitSupport}}</td>
diff --git a/modules-available/systemstatus/page.inc.php b/modules-available/systemstatus/page.inc.php
index 958e763f..04423eaf 100644
--- a/modules-available/systemstatus/page.inc.php
+++ b/modules-available/systemstatus/page.inc.php
@@ -209,7 +209,7 @@ class Page_SystemStatus extends Page
$data['swapTotal'] = Util::readableFileSize($info['SwapTotal'] * 1024);
$data['swapUsed'] = Util::readableFileSize(($info['SwapTotal'] - $info['SwapFree']) * 1024);
$data['swapPercent'] = 100 - round(($info['SwapFree'] / $info['SwapTotal']) * 100);
- $data['swapWarning'] = ($data['swapPercent'] > 50 || ($info['SwapTotal'] - $info['SwapFree']) > 200000);
+ $data['swapWarning'] = ($data['swapPercent'] > 50 || $info['SwapFree'] < 400000);
}
if (isset($info['CpuIdle']) && isset($info['CpuSystem']) && isset($info['CpuTotal'])) {
$data['cpuLoad'] = 100 - round(($info['CpuIdle'] / $info['CpuTotal']) * 100);
diff --git a/style/default.css b/style/default.css
index 6b0c28f6..6c2beb86 100644
--- a/style/default.css
+++ b/style/default.css
@@ -76,7 +76,7 @@ body {
}
.slx-table td {
- padding-right: 5px;
+ padding-right: 7px;
padding-bottom: 2px;
}