- {{systemmodel}}
+ {{systemmodel}}
{{cnt}}
--
cgit v1.2.3-55-g7522
From 313d1c1dfb15de455cc5a8e4952eccfed5fba159 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Fri, 18 Jan 2019 16:57:16 +0100
Subject: [serversetup-bwlp] Fix saving default; add missing lang tag
---
modules-available/serversetup-bwlp/api.inc.php | 2 +-
modules-available/serversetup-bwlp/lang/de/template-tags.json | 1 +
modules-available/serversetup-bwlp/page.inc.php | 3 ++-
modules-available/serversetup-bwlp/templates/localboot.html | 2 +-
4 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/modules-available/serversetup-bwlp/api.inc.php b/modules-available/serversetup-bwlp/api.inc.php
index d089584e..6da4c5df 100644
--- a/modules-available/serversetup-bwlp/api.inc.php
+++ b/modules-available/serversetup-bwlp/api.inc.php
@@ -106,7 +106,7 @@ if ($model !== false) {
}
}
if ($localboot === false || !isset($BOOT_METHODS[$localboot])) {
- $localboot = Property::get('serversetup.localboot', 'AUTO');
+ $localboot = Property::get(Localboot::PROPERTY_KEY, 'AUTO');
if (!isset($BOOT_METHODS[$localboot])) {
$localboot = 'AUTO';
}
diff --git a/modules-available/serversetup-bwlp/lang/de/template-tags.json b/modules-available/serversetup-bwlp/lang/de/template-tags.json
index 2b68b3fb..a242be5e 100644
--- a/modules-available/serversetup-bwlp/lang/de/template-tags.json
+++ b/modules-available/serversetup-bwlp/lang/de/template-tags.json
@@ -72,6 +72,7 @@
"lang_seconds": "Sekunden",
"lang_set": "Setzen",
"lang_spacer": "Abstandhalter\/\u00dcberschrift",
+ "lang_systemmodel": "System-Modell",
"lang_title": "Titel",
"lang_typeExecEntry": "Standardeintrag",
"lang_typeScriptEntry": "Benutzerdefiniertes Script",
diff --git a/modules-available/serversetup-bwlp/page.inc.php b/modules-available/serversetup-bwlp/page.inc.php
index 7766050b..6c32cb82 100644
--- a/modules-available/serversetup-bwlp/page.inc.php
+++ b/modules-available/serversetup-bwlp/page.inc.php
@@ -245,7 +245,7 @@ class Page_ServerSetup extends Page
private function showLocalbootConfig()
{
// Default setting
- $default = Property::get('serversetup.localboot', false);
+ $default = Property::get(Localboot::PROPERTY_KEY, 'AUTO');
if (!array_key_exists($default, Localboot::BOOT_METHODS)) {
$default = 'AUTO';
}
@@ -796,6 +796,7 @@ class Page_ServerSetup extends Page
Message::addError('localboot-invalid-method', $default);
return;
}
+ Property::set(Localboot::PROPERTY_KEY, $default);
$overrides = Request::post('override', [], 'array');
Database::exec('TRUNCATE TABLE serversetup_localboot');
foreach ($overrides as $model => $mode) {
diff --git a/modules-available/serversetup-bwlp/templates/localboot.html b/modules-available/serversetup-bwlp/templates/localboot.html
index 960f463d..3037de2a 100644
--- a/modules-available/serversetup-bwlp/templates/localboot.html
+++ b/modules-available/serversetup-bwlp/templates/localboot.html
@@ -25,7 +25,7 @@
- {{lang_name}}
+ {{lang_systemmodel}}
{{lang_count}}
{{lang_override}}
--
cgit v1.2.3-55-g7522
From d42a3b1f1d30d54f89ff4830163b00364f775e83 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Mon, 21 Jan 2019 12:19:35 +0100
Subject: [statistics] Improve ID44 filter matching
---
modules-available/statistics/inc/filter.inc.php | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/modules-available/statistics/inc/filter.inc.php b/modules-available/statistics/inc/filter.inc.php
index 565ea5f0..3ccea2c3 100644
--- a/modules-available/statistics/inc/filter.inc.php
+++ b/modules-available/statistics/inc/filter.inc.php
@@ -187,20 +187,24 @@ class Id44Filter extends Filter
public function whereClause(&$args, &$joins)
{
global $SIZE_ID44;
- $lower = floor(Page_Statistics::findBestValue($SIZE_ID44, $this->argument, false) * 1024 - 100);
- $upper = ceil(Page_Statistics::findBestValue($SIZE_ID44, $this->argument, true) * 1024 + 100);
+ if ($this->operator === '=' || $this->operator === '!=') {
+ $lower = floor(Page_Statistics::findBestValue($SIZE_ID44, $this->argument, false) * 1024 - 100);
+ $upper = ceil(Page_Statistics::findBestValue($SIZE_ID44, $this->argument, true) * 1024 + 100);
+ } else {
+ $lower = $upper = round($this->argument * 1024);
+ }
- if ($this->operator == '=') {
+ if ($this->operator === '=') {
return " id44mb BETWEEN $lower AND $upper";
- } elseif ($this->operator == '!=') {
+ } elseif ($this->operator === '!=') {
return " id44mb < $lower OR id44mb > $upper";
- } elseif ($this->operator == '<=') {
- return " id44mb < $upper";
- } elseif ($this->operator == '>=') {
- return " id44mb > $lower";
- } elseif ($this->operator == '<') {
+ } elseif ($this->operator === '<=') {
+ return " id44mb <= $upper";
+ } elseif ($this->operator === '>=') {
+ return " id44mb >= $lower";
+ } elseif ($this->operator === '<') {
return " id44mb < $lower";
- } elseif ($this->operator == '>') {
+ } elseif ($this->operator === '>') {
return " id44mb > $upper";
} else {
error_log("unimplemented operator in Id44Filter: $this->operator");
--
cgit v1.2.3-55-g7522
From 54a516de8a49bdcdd2b95ecbfe2a365a860adaf4 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Mon, 21 Jan 2019 14:49:54 +0100
Subject: [statistics] Log if client seems to have crashed
Log when we reset a client's state in the cron job, as well as if we
receive a poweron event even though the state in the DB is still IDLE or
OCCUPIED.
---
modules-available/statistics/api.inc.php | 17 +++++++++++++++++
modules-available/statistics/hooks/cron.inc.php | 13 +++++++++++++
2 files changed, 30 insertions(+)
diff --git a/modules-available/statistics/api.inc.php b/modules-available/statistics/api.inc.php
index 8f5e9fd0..674cc48d 100644
--- a/modules-available/statistics/api.inc.php
+++ b/modules-available/statistics/api.inc.php
@@ -161,6 +161,11 @@ if ($type{0} === '~') {
// Check for suspicious hardware changes
if ($old !== false) {
checkHardwareChange($old, $new);
+
+ // 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']);
+ }
}
// Write statistics data
@@ -403,6 +408,18 @@ 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} === '.') {
diff --git a/modules-available/statistics/hooks/cron.inc.php b/modules-available/statistics/hooks/cron.inc.php
index 4df7b0d4..f05762bc 100644
--- a/modules-available/statistics/hooks/cron.inc.php
+++ b/modules-available/statistics/hooks/cron.inc.php
@@ -23,6 +23,19 @@ 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
+ // Query for logging
+ $res = Database::simpleQuery("SELECT machineuuid, clientip, state 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'],
+ 'longdesc' => '',
+ 'uuid' => $row['machineuuid'],
+ ));
+ }
+ // 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'");
}
--
cgit v1.2.3-55-g7522
From ed383e2562c6ecf219620f17f87eba3ddaf8d335 Mon Sep 17 00:00:00 2001
From: Christian Hofmaier
Date: Tue, 22 Jan 2019 12:27:45 +0100
Subject: [locationinfo] some design rework - Change "free" to "open" - h/min
display in summary - do not display colors of unused states in summary -
change seatcounter to emDash when room has current event
---
modules-available/locationinfo/lang/de/template-tags.json | 3 ++-
modules-available/locationinfo/lang/en/template-tags.json | 3 ++-
.../locationinfo/templates/frontend-default.html | 11 ++++-------
.../locationinfo/templates/frontend-summary.html | 9 +++++++--
4 files changed, 15 insertions(+), 11 deletions(-)
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/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:
{{lang_room}}
{{lang_closed}}
{{lang_free}}
+ {{lang_for}}
{{lang_shortSun}}
{{lang_shortMon}}
{{lang_shortTue}}
@@ -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 @@
{{lang_room}}
{{lang_closed}}
{{lang_free}}
+ {{lang_for}}
{{lang_shortSun}}
{{lang_shortMon}}
{{lang_shortTue}}
--
cgit v1.2.3-55-g7522
From 0a040966751e4a45fc9b9ac6cbaaea100b38ce53 Mon Sep 17 00:00:00 2001
From: Christian Hofmaier
Date: Tue, 22 Jan 2019 16:12:28 +0100
Subject: [inc/Render] new optional argument to change rendered language
---
inc/render.inc.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
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])) {
--
cgit v1.2.3-55-g7522
From e4ff8937a3e0da4c23a97014ade75c15ae456931 Mon Sep 17 00:00:00 2001
From: Christian Hofmaier
Date: Tue, 22 Jan 2019 16:13:26 +0100
Subject: [locationinfo] use set config language for panels
---
modules-available/locationinfo/page.inc.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
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);
--
cgit v1.2.3-55-g7522
From d809112f111e302f5a2be4c5b7eaa9b4e6293c44 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Thu, 24 Jan 2019 12:04:07 +0100
Subject: [serversetup-bwlp] Fix case of platform var
---
modules-available/serversetup-bwlp/api.inc.php | 1 +
modules-available/serversetup-bwlp/inc/localboot.inc.php | 4 +---
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/modules-available/serversetup-bwlp/api.inc.php b/modules-available/serversetup-bwlp/api.inc.php
index 6da4c5df..1df0e6e7 100644
--- a/modules-available/serversetup-bwlp/api.inc.php
+++ b/modules-available/serversetup-bwlp/api.inc.php
@@ -59,6 +59,7 @@ goto retry
HERE;
exit;
}
+// ipxe has it lowercase, but we use uppercase
$platform = strtoupper($platform);
$BOOT_METHODS = Localboot::BOOT_METHODS;
diff --git a/modules-available/serversetup-bwlp/inc/localboot.inc.php b/modules-available/serversetup-bwlp/inc/localboot.inc.php
index a91d0547..3ab81862 100644
--- a/modules-available/serversetup-bwlp/inc/localboot.inc.php
+++ b/modules-available/serversetup-bwlp/inc/localboot.inc.php
@@ -6,12 +6,10 @@ class Localboot
const PROPERTY_KEY = 'serversetup.localboot';
const BOOT_METHODS = [
- 'AUTO' => 'iseq EFI ${platform} && exit 1 || sanboot --no-describe',
+ 'AUTO' => 'iseq efi ${platform} && exit 1 || sanboot --no-describe',
'EXIT' => 'exit 1',
'COMBOOT' => 'chain /tftp/chain.c32 hd0',
'SANBOOT' => 'sanboot --no-describe',
];
-
-
}
\ No newline at end of file
--
cgit v1.2.3-55-g7522
From c124192e63bd8a48ed1e7caf9542dc52505dfd22 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Thu, 24 Jan 2019 12:17:07 +0100
Subject: [statistics] Handling of standby state in statistics, log crashes
Or rather, not really crashes, but log whenever a client reports a
poweron event without reporting a proper shutdown first. This isn't
neccessarily a crash but could also be due to power loss, hard poweroff,
or network failures.
---
modules-available/statistics/api.inc.php | 102 +++++++++------------
modules-available/statistics/hooks/cron.inc.php | 20 +++-
modules-available/statistics/inc/parser.inc.php | 10 +-
.../statistics/inc/statistics.inc.php | 17 ++++
modules-available/statistics/page.inc.php | 29 +++++-
5 files changed, 107 insertions(+), 71 deletions(-)
diff --git a/modules-available/statistics/api.inc.php b/modules-available/statistics/api.inc.php
index 674cc48d..813e7d54 100644
--- a/modules-available/statistics/api.inc.php
+++ b/modules-available/statistics/api.inc.php
@@ -123,32 +123,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);
}
}
}
@@ -173,36 +161,41 @@ 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'];
+ }
+ }
+ }
+ }
+ // 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 +225,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 +233,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 +349,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 +424,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..0b8e740e 100644
--- a/modules-available/statistics/hooks/cron.inc.php
+++ b/modules-available/statistics/hooks/cron.inc.php
@@ -21,10 +21,11 @@ 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 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(
@@ -34,9 +35,20 @@ function state_cleanup()
'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/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/page.inc.php b/modules-available/statistics/page.inc.php
index abacc8d2..2d86615e 100644
--- a/modules-available/statistics/page.inc.php
+++ b/modules-available/statistics/page.inc.php
@@ -910,16 +910,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 +947,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 +972,26 @@ class Page_Statistics extends Page
}
if ($client['state'] === 'OCCUPIED') {
$spans['graph'] .= '
';
+ $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'] .= '
';
+ $spans['rows'][] = [
+ 'from' => Util::prettyTime($client['lastseen']),
+ 'duration' => '-',
+ 'glyph' => 'off',
+ ];
+ } elseif ($client['state'] === 'STANDBY') {
+ $spans['graph'] .= '
';
+ $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) {
--
cgit v1.2.3-55-g7522
From ab6171159d5471ea1d4c1be0736ef8db230f5dcc Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Thu, 24 Jan 2019 14:00:31 +0100
Subject: [default.css] Make slx-table columns a bit wider
---
style/default.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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;
}
--
cgit v1.2.3-55-g7522
From 9ae2c70073490a253ccf2fcb567d57b07811389b Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Thu, 24 Jan 2019 17:31:38 +0100
Subject: [statistics] Minor refactoring (PHP >= 5.6)
---
modules-available/statistics/inc/filter.inc.php | 16 ++++---
modules-available/statistics/page.inc.php | 58 ++++++++++++-------------
2 files changed, 38 insertions(+), 36 deletions(-)
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/page.inc.php b/modules-available/statistics/page.inc.php
index 2d86615e..c9a0cac5 100644
--- a/modules-available/statistics/page.inc.php
+++ b/modules-available/statistics/page.inc.php
@@ -1,7 +1,6 @@
=', '=', '<', '>'];
+ const OP_STRCMP = ['!~', '~', '=', '!='];
public static $columns;
private $query;
@@ -27,123 +26,120 @@ 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,
+ 'op' => Page_Statistics::OP_NOMINAL,
'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');
@@ -1127,3 +1123,5 @@ class Page_Statistics extends Page
), true);
}
}
+
+Page_Statistics::initConstants();
--
cgit v1.2.3-55-g7522
From 54a0a4c9b920bce1dc4e93d2cf05ebbea6502be0 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Mon, 28 Jan 2019 13:48:03 +0100
Subject: [inc/Util] readableFileSize: support input in KB/MB/...
---
inc/util.inc.php | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
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)
--
cgit v1.2.3-55-g7522
From 3b1df888c963d906005ff139892df06a0d1ae2b4 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Mon, 28 Jan 2019 13:48:35 +0100
Subject: [statistics] Track and display memory/tmp usage of clients
---
modules-available/statistics/api.inc.php | 13 ++++++--
modules-available/statistics/hooks/cron.inc.php | 9 ++++--
modules-available/statistics/install.inc.php | 17 ++++++++++
.../statistics/lang/de/template-tags.json | 4 +++
.../statistics/lang/en/template-tags.json | 4 +++
modules-available/statistics/page.inc.php | 37 ++++++++++++++++------
modules-available/statistics/style.css | 32 +++++++++++++++++++
.../statistics/templates/filterbox.html | 5 ++-
.../statistics/templates/machine-main.html | 33 ++++++++++++++++---
9 files changed, 135 insertions(+), 19 deletions(-)
diff --git a/modules-available/statistics/api.inc.php b/modules-available/statistics/api.inc.php
index 813e7d54..57c4cee2 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 '
@@ -152,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_memfree'], -1, 2));
}
}
@@ -190,6 +195,10 @@ if ($type{0} === '~') {
}
}
}
+ 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') {
if ($old['state'] === 'OCCUPIED' && $sessionLength === 0) {
diff --git a/modules-available/statistics/hooks/cron.inc.php b/modules-available/statistics/hooks/cron.inc.php
index 0b8e740e..f22d0475 100644
--- a/modules-available/statistics/hooks/cron.inc.php
+++ b/modules-available/statistics/hooks/cron.inc.php
@@ -24,14 +24,17 @@ function state_cleanup()
$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, logintime, lastseen 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_memfree'], -1, 2),
'longdesc' => '',
'uuid' => $row['machineuuid'],
));
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 c9a0cac5..a9cde6fb 100644
--- a/modules-available/statistics/page.inc.php
+++ b/modules-available/statistics/page.inc.php
@@ -122,8 +122,18 @@ class Page_Statistics extends Page
'column' => true,
'values' => ['occupied', 'on', 'off', 'idle', 'standby']
],
- 'runtime' => [
- 'op' => Page_Statistics::OP_NOMINAL,
+ '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
],
@@ -764,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'"
@@ -783,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);
@@ -826,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 {
@@ -835,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']);
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..904c780b 100644
--- a/modules-available/statistics/templates/machine-main.html
+++ b/modules-available/statistics/templates/machine-main.html
@@ -1,3 +1,4 @@
+{{%FILTERS}}
{{hostname}} {{#hostname}}–{{/hostname}} {{clientip}}
{{#notes}} {{/notes}}
@@ -117,9 +118,23 @@
{{lang_ram}}
- {{gbram}} GiB
- {{#maxram}}({{lang_maximumAbbrev}} {{maxram}}){{/maxram}}
- {{ramtype}}
+
+ {{gbram}} GiB
+ {{#maxram}}({{lang_maximumAbbrev}} {{maxram}}){{/maxram}}
+ {{ramtype}}
+
+ {{#live_memsize}}
+
+
{{live_memfree_s}} {{lang_free}}
+
+
+ {{/live_memsize}}
+ {{#live_swapsize}}
+
+
{{live_swapfree_s}} {{lang_free}}
+
+
+ {{/live_swapsize}}
{{#extram}}
@@ -135,7 +150,17 @@
{{/extram}}
{{lang_tempPart}}
- {{gbtmp}} GiB
+
+
+ {{gbtmp}} GiB
+
+ {{#live_tmpsize}}
+
+
{{live_tmpfree_s}} {{lang_free}}
+
+
+ {{/live_tmpsize}}
+
{{lang_64bitSupport}}
--
cgit v1.2.3-55-g7522
From 8c5c14eb4ad2fcaeb35d746d2183943f6dc52fb1 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Mon, 28 Jan 2019 14:33:16 +0100
Subject: [statistics] Cleanup template
---
modules-available/statistics/templates/machine-main.html | 1 -
1 file changed, 1 deletion(-)
diff --git a/modules-available/statistics/templates/machine-main.html b/modules-available/statistics/templates/machine-main.html
index 904c780b..44f03a99 100644
--- a/modules-available/statistics/templates/machine-main.html
+++ b/modules-available/statistics/templates/machine-main.html
@@ -1,4 +1,3 @@
-{{%FILTERS}}
{{hostname}} {{#hostname}}–{{/hostname}} {{clientip}}
{{#notes}} {{/notes}}
--
cgit v1.2.3-55-g7522
From 1b53e1ac441f547e4524a512eff3d6b25457f95e Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Mon, 28 Jan 2019 14:38:47 +0100
Subject: [statistics] Fix copypasta
---
modules-available/statistics/api.inc.php | 2 +-
modules-available/statistics/hooks/cron.inc.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/modules-available/statistics/api.inc.php b/modules-available/statistics/api.inc.php
index 57c4cee2..280e5abc 100644
--- a/modules-available/statistics/api.inc.php
+++ b/modules-available/statistics/api.inc.php
@@ -157,7 +157,7 @@ if ($type{0} === '~') {
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_memfree'], -1, 2));
+ . ', ID44: ' . Util::readableFileSize($old['live_tmpfree'], -1, 2));
}
}
diff --git a/modules-available/statistics/hooks/cron.inc.php b/modules-available/statistics/hooks/cron.inc.php
index f22d0475..6393b2c6 100644
--- a/modules-available/statistics/hooks/cron.inc.php
+++ b/modules-available/statistics/hooks/cron.inc.php
@@ -34,7 +34,7 @@ function state_cleanup()
'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_memfree'], -1, 2),
+ . ', ID44: ' . Util::readableFileSize($row['live_tmpfree'], -1, 2),
'longdesc' => '',
'uuid' => $row['machineuuid'],
));
--
cgit v1.2.3-55-g7522
From 533a2964535bcae48eb30ded2edaa6dd6d2c321b Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Tue, 29 Jan 2019 09:20:55 +0100
Subject: [locationinfo] Suppress XML parsing error spam
The SimpleXML constructor is quite verbose if you pass it e.g. an HTML
error page instead of the expected XML. Suppress those errors, we'll do
our own (more concise) logging in the exception handler.
---
modules-available/locationinfo/inc/coursebackend.inc.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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) {
--
cgit v1.2.3-55-g7522
From f538335087e18ad5950eee0ec1c9654fff5addc5 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Tue, 29 Jan 2019 09:22:28 +0100
Subject: [locationinfo] HisInOne: Properly handle multiple plannedDates
If a course has been running for several semesters, older plannedDate
entries tend to have no individualDate entries. Ignore those and don't
error_log about it.
---
.../locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php | 7 +++++++
1 file changed, 7 insertions(+)
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) {
--
cgit v1.2.3-55-g7522
From 16c94742e46834336d77ca6825fa681db9c966bb Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Wed, 30 Jan 2019 13:24:03 +0100
Subject: [systemstatus] Don't show swap warning too early
---
modules-available/systemstatus/page.inc.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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);
--
cgit v1.2.3-55-g7522
From 120956761383f8365e95e669a11b344af4764c74 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Wed, 30 Jan 2019 13:39:41 +0100
Subject: [inc/Dictionary] Teh evil unvalidated redirects must die!
---
inc/dictionary.inc.php | 11 ++++++++---
1 file changed, 8 insertions(+), 3 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);
}
--
cgit v1.2.3-55-g7522
From 1ee6bdcda1b285b24829eefc9b9e0ca14b828f77 Mon Sep 17 00:00:00 2001
From: Udo Walter
Date: Tue, 12 Feb 2019 11:44:51 +0100
Subject: [dozmod] Add UI to create preset network rules
---
modules-available/dozmod/lang/de/messages.json | 6 ++
modules-available/dozmod/lang/de/module.json | 1 +
modules-available/dozmod/lang/de/permissions.json | 2 +
.../dozmod/lang/de/template-tags.json | 4 +
modules-available/dozmod/lang/en/messages.json | 6 ++
modules-available/dozmod/lang/en/module.json | 1 +
modules-available/dozmod/lang/en/permissions.json | 2 +
.../dozmod/lang/en/template-tags.json | 4 +
modules-available/dozmod/page.inc.php | 2 +-
.../dozmod/pages/networkrules.inc.php | 98 ++++++++++++++++++++++
.../dozmod/permissions/permissions.json | 6 ++
.../dozmod/templates/networkrules-edit.html | 43 ++++++++++
.../dozmod/templates/networkrules.html | 82 ++++++++++++++++++
13 files changed, 256 insertions(+), 1 deletion(-)
create mode 100644 modules-available/dozmod/pages/networkrules.inc.php
create mode 100644 modules-available/dozmod/templates/networkrules-edit.html
create mode 100644 modules-available/dozmod/templates/networkrules.html
diff --git a/modules-available/dozmod/lang/de/messages.json b/modules-available/dozmod/lang/de/messages.json
index 4a4be923..805472d0 100644
--- a/modules-available/dozmod/lang/de/messages.json
+++ b/modules-available/dozmod/lang/de/messages.json
@@ -11,6 +11,12 @@
"ldap-filter-saved": "LDAP Filter wurde erfolgreich gespeichert",
"ldap-invalid-filter-id": "Ung\u00fcltige LDAP Filter ID",
"mail-config-saved": "Mail-Konfiguration gespeichert",
+ "networkrule-deleted": "Netzwerk-Regel gel\u00f6scht",
+ "networkrule-invalid-direction": "Ung\u00fcltige Richtung: {{0}}",
+ "networkrule-invalid-ruleid": "Nicht-existierende Regel: {{0}}",
+ "networkrule-missing-host": "Fehlende Hostangabe",
+ "networkrule-missing-port": "Fehlende Portangabe",
+ "networkrule-saved": "Netzwerk-Regel gespeichert",
"networkshare-deleted": "Netzlaufwerk gel\u00f6scht",
"networkshare-invalid-auth-type": "Ung\u00fcltiger Authentifizierungs-Typ: {{0}}",
"networkshare-invalid-shareid": "Nicht-existierender Share: {{0}}",
diff --git a/modules-available/dozmod/lang/de/module.json b/modules-available/dozmod/lang/de/module.json
index 8902852a..ff4519a7 100644
--- a/modules-available/dozmod/lang/de/module.json
+++ b/modules-available/dozmod/lang/de/module.json
@@ -5,6 +5,7 @@
"submenu_expiredimages": "Abgelaufene VM-Versionen",
"submenu_ldapfilters": "LDAP-Filter",
"submenu_mailconfig": "Email-Konfiguration",
+ "submenu_networkrules": "Netzwerk-Regeln",
"submenu_networkshares": "Netzlaufwerke",
"submenu_runscripts": "Startskripte",
"submenu_runtimeconfig": "Limits und Standardwerte",
diff --git a/modules-available/dozmod/lang/de/permissions.json b/modules-available/dozmod/lang/de/permissions.json
index a1675148..6475f7ab 100644
--- a/modules-available/dozmod/lang/de/permissions.json
+++ b/modules-available/dozmod/lang/de/permissions.json
@@ -4,6 +4,8 @@
"ldapfilters.save": "LDAP Filter speichern.",
"ldapfilters.view": "LDAP Filter einsehen.",
"mailconfig.save": "\u00c4nderungen an der SMTP-Konfiguration zum Versenden von Mails speichern.",
+ "networkrules.save": "Netzwerk-Regeln einsehen.",
+ "networkrules.view": "\u00c4nderungen an den Netzwerk-Regeln speichern.",
"networkshares.save": "Netzlaufwerke einsehen.",
"networkshares.view": "\u00c4nderungen an den Netzlaufwerken speichern.",
"runscripts.save": "Startkripte erstellen\/bearbeiten",
diff --git a/modules-available/dozmod/lang/de/template-tags.json b/modules-available/dozmod/lang/de/template-tags.json
index 0a719057..320c7592 100644
--- a/modules-available/dozmod/lang/de/template-tags.json
+++ b/modules-available/dozmod/lang/de/template-tags.json
@@ -1,6 +1,7 @@
{
"lang_actionTarget": "Aktionsziel",
"lang_active": "Aktiv",
+ "lang_addRule": "Netzwerk-Regel hinzuf\u00fcgen",
"lang_addShare": "Netzlaufwerk hinzuf\u00fcgen",
"lang_allowLoginByDefault": "Login standardm\u00e4\u00dfig erlauben",
"lang_allowLoginDescription": "Wenn diese Option aktiviert ist, k\u00f6nnen sich alle Mitarbeiter der Einrichtung \u00fcber die bwLehrpool-Suite anmelden und VMs\/Veranstaltungen verwalten. Wenn Sie diese Option deaktivieren, m\u00fcssen Sie in der Untersektion \"Benutzer und Berechtigungen\" jeden Benutzer nach dem ersten Loginversuch manuell freischalten.",
@@ -23,7 +24,9 @@
"lang_descriptionPermissionConfig": "Dies sind die Berechtigungen, die ein Benutzer standardm\u00e4\u00dfig f\u00fcr fremde VMs\/Veranstaltungen hat. Sie werden angewandt, wenn der Besitzer keine anderweitigen Berechtigungen w\u00e4hlt.",
"lang_descriptionRuntimeLimits": "Hier k\u00f6nnen Sie verschiedene Limits festlegen, z.B. wie lange eine VM nach dem Hochladen g\u00fcltig ist. Nach Ablauf dieses Zeitraums ist der Verantwortliche gezwungen, eine neue Version der VM hochzuladen. Damit k\u00f6nnen Sie das Ansammeln nicht mehr ben\u00f6tigter VMs eind\u00e4mmen. Weiterhin k\u00f6nnen Sie die maximale Anzahl gleichzeitiger Transfers pro Benutzer einschr\u00e4nken.\r\n\r\nVer\u00e4nderte Einstellungen wirken sich nicht auf bereits bestehende VMs aus.",
"lang_description_delete_images": "Diese Liste zeigt VMs, die entweder abgelaufen sind, oder deren Datei besch\u00e4digt, verschoben oder gel\u00f6scht wurde. Diese Images sind zur Zeit im Lehrpool nicht verf\u00fcgbar, ihre endg\u00fcltige L\u00f6schung muss aber manuell best\u00e4tigt werden, um gr\u00f6\u00dfere Katastrophen durch Softwarefehler, verstellte Systemuhren etc. zu vermeiden.",
+ "lang_direction": "Richtung",
"lang_dozmodLogHeading": "bwLehrpool-Suite Aktionslog",
+ "lang_editNetworkrule": "Netzwerk-Regel bearbeiten",
"lang_editNetworkshare": "Netzlaufwerk bearbeiten",
"lang_editScript": "Startscript bearbeiten",
"lang_email": "EMail",
@@ -66,6 +69,7 @@
"lang_miscOptions": "Verschiedene Einstellungen",
"lang_modified": "Modifiziert",
"lang_name": "Name",
+ "lang_networkrules": "Netzwerk-Regeln",
"lang_networkshares": "Netzlaufwerke",
"lang_networksharesIntro": "Hier k\u00f6nnen Sie vordefinierte Netzlaufwerke anlegen, die den Nutzern der bwLehrpool-Suite zur Auswahl gestellt werden. Es ist den Nutzern der bwLehrpool-Suite weiterhin m\u00f6glich, komplett eigene Netzwerkfreigaben zu definieren. Die Angaben hier sollen lediglich das Hinzuf\u00fcgen h\u00e4ufig genutzter Laufwerke vereinfachen, bzw. das \u00c4ndern eines Netzwerkpfades vereinfachen, da in diesem Fall nur der Zentrale Eintrag hier angepasst werden muss, und nicht mehr wie zuvor jede Veranstaltung einzeln.",
"lang_none": "(Keiner)",
diff --git a/modules-available/dozmod/lang/en/messages.json b/modules-available/dozmod/lang/en/messages.json
index d09ff279..6d8296ec 100644
--- a/modules-available/dozmod/lang/en/messages.json
+++ b/modules-available/dozmod/lang/en/messages.json
@@ -11,6 +11,12 @@
"ldap-filter-saved": "Successfully modified LDAP filter",
"ldap-invalid-filter-id": "Invalid LDAP filter id",
"mail-config-saved": "Mail config saved",
+ "networkrule-deleted": "Network rule deleted",
+ "networkrule-invalid-direction": "Invalid direction: {{0}}",
+ "networkrule-invalid-ruleid": "Invalid rule id: {{0}}",
+ "networkrule-missing-host": "Missing host",
+ "networkrule-missing-port": "Missing port",
+ "networkrule-saved": "Network rule saved",
"networkshare-deleted": "Network share deleted",
"networkshare-invalid-auth-type": "Invalid auth type: {{0}}",
"networkshare-invalid-shareid": "Invalid share id: {{0}}",
diff --git a/modules-available/dozmod/lang/en/module.json b/modules-available/dozmod/lang/en/module.json
index 4e3969ff..8967493d 100644
--- a/modules-available/dozmod/lang/en/module.json
+++ b/modules-available/dozmod/lang/en/module.json
@@ -5,6 +5,7 @@
"submenu_expiredimages": "Expired VM versions",
"submenu_ldapfilters": "LDAP filters",
"submenu_mailconfig": "email configuration",
+ "submenu_networkrules": "Network Rules",
"submenu_networkshares": "Network Shares",
"submenu_runtimeconfig": "limits and defaults",
"submenu_templates": "templates",
diff --git a/modules-available/dozmod/lang/en/permissions.json b/modules-available/dozmod/lang/en/permissions.json
index d45e5207..dec3171a 100644
--- a/modules-available/dozmod/lang/en/permissions.json
+++ b/modules-available/dozmod/lang/en/permissions.json
@@ -4,6 +4,8 @@
"ldapfilters.save": "Save LDAP filter.",
"ldapfilters.view": "View LDAP filters. ",
"mailconfig.save": "Save SMTP configuration for sending mails.",
+ "networkrules.save": "View network rules.",
+ "networkrules.view": "Save network rules.",
"networkshares.save": "View network drives.",
"networkshares.view": "Save network drives.",
"runtimeconfig.save": "Save limits and defaults of a runtime configuration.",
diff --git a/modules-available/dozmod/lang/en/template-tags.json b/modules-available/dozmod/lang/en/template-tags.json
index ddc89284..3f2ae1fc 100644
--- a/modules-available/dozmod/lang/en/template-tags.json
+++ b/modules-available/dozmod/lang/en/template-tags.json
@@ -1,6 +1,7 @@
{
"lang_actionTarget": "Action target",
"lang_active": "Active",
+ "lang_addRule": "Add Network Rule",
"lang_addShare": "Add Network Share",
"lang_allowLoginByDefault": "Allow all staff members to login and use the bwLehrpool-Suite",
"lang_allowLoginDescription": "If this option is enabled, all members of the organization marked as staff or employee are allowed to login to this server and manage VMs\/courses. Otherwise, new users need to be individually allowed access after their first login attempt by visiting the sub page \"users and permissions\" in this web interface.",
@@ -23,7 +24,9 @@
"lang_descriptionPermissionConfig": "These are the default permissions being used for VMs and lectures if the owner does not specify any.",
"lang_descriptionRuntimeLimits": "Here you can define some limits, e.g. how long a newly uploaded VM will be valid. This should make sure that you don't end up with a lot of old, unused VMs over time.\r\n\r\nModified settings won't apply for already existing VMs.",
"lang_description_delete_images": "This is a list of VMs that either expired, or where the disk image is damaged or missing. These VMs are not available in bwLehrpool currently, but you have to manually confirm the deletion of the disk images for safety reasons (clock skew etc.)",
+ "lang_direction": "Direction",
"lang_dozmodLogHeading": "bwLehrpool-Suite action log",
+ "lang_editNetworkrule": "Edit Network Rule",
"lang_editNetworkshare": "Edit Network Share",
"lang_email": "E-Mail",
"lang_emailNotifications": "E-Mail notifications enabled",
@@ -63,6 +66,7 @@
"lang_miscOptions": "Misc options",
"lang_modified": "modified",
"lang_name": "Name",
+ "lang_networkrules": "Network Rules",
"lang_networkshares": "Network Shares",
"lang_networksharesIntro": "This is the list of predefined network shares. bwLehrpool-Suite users can still add custom network shares to their lectures, however having commonly used network shares as predefined entries should be much more convenient. Another advantage is that changing the path of a network share centrally avoids having to edit a dozen lectures' configuration manually.",
"lang_none": "(none)",
diff --git a/modules-available/dozmod/page.inc.php b/modules-available/dozmod/page.inc.php
index 776109cf..b772890f 100644
--- a/modules-available/dozmod/page.inc.php
+++ b/modules-available/dozmod/page.inc.php
@@ -5,7 +5,7 @@ class Page_DozMod extends Page
/** @var bool true if we have a proper subpage */
private $haveSubPage = false;
- private $validSections = ['expiredimages', 'mailconfig', 'templates', 'runtimeconfig', 'users', 'actionlog', 'networkshares', 'ldapfilters', 'runscripts'];
+ private $validSections = ['expiredimages', 'mailconfig', 'templates', 'runtimeconfig', 'users', 'actionlog', 'networkshares', 'ldapfilters', 'runscripts', 'networkrules'];
private $section;
diff --git a/modules-available/dozmod/pages/networkrules.inc.php b/modules-available/dozmod/pages/networkrules.inc.php
new file mode 100644
index 00000000..6011e3ff
--- /dev/null
+++ b/modules-available/dozmod/pages/networkrules.inc.php
@@ -0,0 +1,98 @@
+ $ruleid]);
+ if ($res !== false) {
+ Message::addSuccess('networkrule-deleted');
+ }
+ }
+ } else if ($action === 'save') {
+ User::assertPermission('networkrules.save');
+ $ruleid = Request::post('ruleid', 0, 'int');
+ $rulename = Request::post('rulename', '', 'string');
+ $host = Request::post('host', '', 'string');
+ $port = Request::post('port', '', 'string');
+ $direction = Request::post('direction', '', 'string');
+
+ if (!in_array($direction, ['IN', 'OUT'], true)) {
+ Message::addError('networkrule-invalid-direction', $direction);
+ } elseif (empty($host)) {
+ Message::addError('networkrule-missing-host');
+ } elseif (empty($port)) {
+ Message::addError('networkrule-missing-port');
+ } else {
+ $data = json_encode([
+ 'host' => $host,
+ 'port' => $port,
+ 'direction' => $direction
+ ]);
+ if ($ruleid !== 0) {
+ Database::exec('UPDATE sat.presetnetworkrules SET rulename = :rulename, ruledata = :data'
+ .' WHERE ruleid = :ruleid', compact('ruleid', 'rulename', 'data'));
+ } else {
+ Database::exec('INSERT INTO sat.presetnetworkrules (rulename, ruledata)'
+ .' VALUES (:rulename, :data)', compact('rulename', 'data'));
+ }
+ Message::addSuccess('networkrule-saved');
+ }
+ }
+ if (Request::isPost()) {
+ Util::redirect('?do=dozmod§ion=networkrules');
+ }
+ User::assertPermission('networkrules.view');
+ }
+
+ public static function doRender()
+ {
+ $show = Request::get('show', 'list', 'string');
+ if ($show === 'list') {
+ $res = Database::simpleQuery('SELECT ruleid, rulename, ruledata
+ FROM sat.presetnetworkrules ORDER BY rulename ASC');
+ $rows = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $dec = json_decode($row['ruledata'], true);
+ if (!is_array($dec)) {
+ $dec = [];
+ }
+ $rows[] = $row + $dec;
+ }
+ Render::addTemplate('networkrules', [
+ 'networkrules' => $rows,
+ 'hasEditPermissions' => User::hasPermission('networkrules.save')
+ ]);
+ } else if ($show === 'edit') {
+ $ruleid = Request::get('ruleid', 0, 'int');
+ if ($ruleid === 0) {
+ $data = [];
+ } else {
+ $data = Database::queryFirst('SELECT ruleid, rulename, ruledata
+ FROM sat.presetnetworkrules WHERE ruleid = :ruleid', ['ruleid' => $ruleid]);
+ if ($data === false) {
+ Message::addError('networkrule-invalid-ruleid', $ruleid);
+ Util::redirect('?do=dozmod§ion=networkrules');
+ }
+ $dec = json_decode($data['ruledata'], true);
+ if (is_array($dec)) {
+ $data += $dec;
+ }
+ if ($data['direction'] === 'IN') {
+ $data['inSelected'] = 'selected';
+ } else {
+ $data['outSelected'] = 'selected';
+ }
+ }
+ Render::addTemplate('networkrules-edit', $data);
+ }
+ }
+
+}
diff --git a/modules-available/dozmod/permissions/permissions.json b/modules-available/dozmod/permissions/permissions.json
index 3f9cd604..c8958089 100644
--- a/modules-available/dozmod/permissions/permissions.json
+++ b/modules-available/dozmod/permissions/permissions.json
@@ -14,6 +14,12 @@
"mailconfig.save": {
"location-aware": false
},
+ "networkrules.view": {
+ "location-aware": false
+ },
+ "networkrules.save": {
+ "location-aware": false
+ },
"networkshares.view": {
"location-aware": false
},
diff --git a/modules-available/dozmod/templates/networkrules-edit.html b/modules-available/dozmod/templates/networkrules-edit.html
new file mode 100644
index 00000000..c04e2825
--- /dev/null
+++ b/modules-available/dozmod/templates/networkrules-edit.html
@@ -0,0 +1,43 @@
+{{lang_networkrules}}
+
+
+
+ {{lang_editNetworkrule}}
+
+
+
\ No newline at end of file
diff --git a/modules-available/dozmod/templates/networkrules.html b/modules-available/dozmod/templates/networkrules.html
new file mode 100644
index 00000000..4344ff4f
--- /dev/null
+++ b/modules-available/dozmod/templates/networkrules.html
@@ -0,0 +1,82 @@
+{{lang_networkrules}}
+
+
+ {{lang_networkrulesIntro}}
+
+
+
+
+
+ {{lang_name}}
+ {{lang_host}}
+ {{lang_port}}
+ {{lang_direction}}
+ {{#hasEditPermissions}}
+ {{lang_edit}}
+ {{lang_delete}}
+ {{/hasEditPermissions}}
+
+
+
+ {{#networkrules}}
+
+ {{rulename}}
+ {{host}}
+ {{port}}
+ {{direction}}
+ {{#hasEditPermissions}}
+
+
+
+
+
+
+
+
+
+
+ {{/hasEditPermissions}}
+
+ {{/networkrules}}
+
+
+{{#hasEditPermissions}}
+
+{{/hasEditPermissions}}
+
+
+
+
+
\ No newline at end of file
--
cgit v1.2.3-55-g7522
From 2d64b9d8f57f28456eb27c4aed2dde26201b6770 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Tue, 12 Feb 2019 14:35:49 +0100
Subject: [serversetup-bwlp] Auto-import of old PXELinux config on bootup
Also minor improvements to UI and structuring
---
inc/event.inc.php | 11 +++
.../serversetup-bwlp/hooks/bootup.inc.php | 11 +++
.../serversetup-bwlp/inc/bootentry.inc.php | 3 +-
.../serversetup-bwlp/inc/ipxe.inc.php | 79 ++++++++++++++++++----
.../serversetup-bwlp/inc/pxelinux.inc.php | 40 +++++++++++
.../serversetup-bwlp/lang/de/messages.json | 12 ++--
.../serversetup-bwlp/lang/de/module.json | 4 +-
.../serversetup-bwlp/lang/de/template-tags.json | 23 ++++---
modules-available/serversetup-bwlp/page.inc.php | 39 +++++++----
.../serversetup-bwlp/templates/bootentry-list.html | 12 +++-
.../templates/ipxe-new-boot-entry.html | 9 ++-
.../serversetup-bwlp/templates/menu-edit.html | 2 +-
.../serversetup-bwlp/templates/menu-list.html | 13 +++-
13 files changed, 211 insertions(+), 47 deletions(-)
create mode 100644 modules-available/serversetup-bwlp/hooks/bootup.inc.php
diff --git a/inc/event.inc.php b/inc/event.inc.php
index b1ee3663..4e68ab6d 100644
--- a/inc/event.inc.php
+++ b/inc/event.inc.php
@@ -24,6 +24,17 @@ class Event
Property::clearList('cron.key.status');
Property::clearList('cron.key.blocked');
+ // Hooks
+ foreach (Hook::load('bootup') as $hook) {
+ // Isolate for local vars
+ $fun = function() use ($hook) {
+ include_once($hook->file);
+ };
+ $fun();
+ }
+
+ // TODO: Modularize (hooks)
+
// Tasks: fire away
$mountStatus = false;
$mountId = Trigger::mount();
diff --git a/modules-available/serversetup-bwlp/hooks/bootup.inc.php b/modules-available/serversetup-bwlp/hooks/bootup.inc.php
new file mode 100644
index 00000000..50ac04ae
--- /dev/null
+++ b/modules-available/serversetup-bwlp/hooks/bootup.inc.php
@@ -0,0 +1,11 @@
+ 0) {
+ EventLog::info('Imported old PXELinux menu, with ' . $num . ' additional IP-range based menus.');
+ } else {
+ EventLog::info('Imported old PXELinux menu.');
+ }
+}
diff --git a/modules-available/serversetup-bwlp/inc/bootentry.inc.php b/modules-available/serversetup-bwlp/inc/bootentry.inc.php
index 010b660c..69adffd3 100644
--- a/modules-available/serversetup-bwlp/inc/bootentry.inc.php
+++ b/modules-available/serversetup-bwlp/inc/bootentry.inc.php
@@ -95,7 +95,7 @@ class StandardBootEntry extends BootEntry
protected $replace;
protected $autoUnload;
protected $resetConsole;
- protected $arch; // true == available, false == not available
+ protected $arch; // Constants below
const BIOS = 'PCBIOS'; // Only valid for legacy BIOS boot
const EFI = 'EFI'; // Only valid for EFI boot
@@ -105,6 +105,7 @@ class StandardBootEntry extends BootEntry
public function __construct($data = false)
{
if ($data instanceof PxeSection) {
+ // Gets arrayfied below
$this->executable = $data->kernel;
$this->initRd = $data->initrd;
$this->commandLine = ' ' . str_replace('vga=current', '', $data->append) . ' ';
diff --git a/modules-available/serversetup-bwlp/inc/ipxe.inc.php b/modules-available/serversetup-bwlp/inc/ipxe.inc.php
index d5bbb4b2..d34839f0 100644
--- a/modules-available/serversetup-bwlp/inc/ipxe.inc.php
+++ b/modules-available/serversetup-bwlp/inc/ipxe.inc.php
@@ -3,8 +3,16 @@
class IPxe
{
+ /**
+ * Import all IP-Range based pxe menus from the given directory.
+ *
+ * @param string $configPath The pxelinux.cfg path where to look for menu files in hexadecimal IP format.
+ * @return Number of menus imported
+ */
public static function importPxeMenus($configPath)
{
+ $importCount = 0;
+ $menus = [];
foreach (glob($configPath . '/*', GLOB_NOSORT) as $file) {
if (!is_file($file) || !preg_match('~/[A-F0-9]{1,8}$~', $file))
continue;
@@ -29,14 +37,53 @@ class IPxe
unset($loc);
$locations[] = $row;
}
- $menuId = self::insertMenu($content, 'Imported', false, 0, [], []);
+ $menu = PxeLinux::parsePxeLinux($content);
+ $key = $menu->hash(true);
+ if (isset($menus[$key])) {
+ $menuId = $menus[$key];
+ $defId = null;
+ // Figure out the default label, get it's label name
+ foreach ($menu->sections as $section) {
+ if ($section->isDefault) {
+ $defId = $section;
+ } elseif ($defId === null && $section->label === $menu->timeoutLabel) {
+ $defId = $section;
+ }
+ }
+ if ($defId !== null) {
+ $defId = self::cleanLabelFixLocal($defId);
+ // Confirm it actually exists (it should since the menu seems identical) and get menuEntryId
+ $me = Database::queryFirst('SELECT m.defaultentryid, me.menuentryid FROM serversetup_bootentry be
+ INNER JOIN serversetup_menuentry me ON (be.entryid = me.entryid)
+ INNER JOIN serversetup_menu m ON (m.menuid = me.menuid)
+ WHERE be.entryid = :id AND me.menuid = :menuid',
+ ['id' => $defId, 'menuid' => $menuId]);
+ if ($me === false || $me['defaultentryid'] == $me['menuentryid']) {
+ $defId = null; // Not found, or is already default - don't override if it's the same
+ } else {
+ $defId = $me['menuentryid'];
+ }
+ }
+ } else {
+ $menuId = self::insertMenu($menu, 'Imported', false, 0, [], []);
+ $menus[$key] = $menuId;
+ $defId = null;
+ $importCount++;
+ }
if ($menuId === false)
continue;
foreach ($locations as $loc) {
- Database::exec('INSERT IGNORE INTO serversetup_menu_x_location (menuid, locationid)
- VALUES (:menuid, :locationid)', ['menuid' => $menuId, 'locationid' => $loc['locationid']]);
+ if ($loc === false)
+ continue;
+ Database::exec('INSERT IGNORE INTO serversetup_menu_location (menuid, locationid, defaultentryid)
+ VALUES (:menuid, :locationid, :def)', [
+ 'menuid' => $menuId,
+ 'locationid' => $loc['locationid'],
+ 'def' => $defId,
+ ]);
}
}
+ return $importCount;
}
public static function importLegacyMenu($force = false)
@@ -76,16 +123,25 @@ class IPxe
'',
'poweroff' => false,
];
- return self::insertMenu($pxeConfig, $menuTitle, $defaultLabel, $timeoutSecs, $prepend, $append);
+ return self::insertMenu(PxeLinux::parsePxeLinux($pxeConfig), $menuTitle, $defaultLabel, $timeoutSecs, $prepend, $append);
}
- private static function insertMenu($pxeConfig, $menuTitle, $defaultLabel, $defaultTimeoutSeconds, $prepend, $append)
+ /**
+ * @param PxeMenu $pxeMenu
+ * @param string $menuTitle
+ * @param string|false $defaultLabel
+ * @param $defaultTimeoutSeconds
+ * @param $prepend
+ * @param $append
+ * @return bool|int
+ */
+ private static function insertMenu($pxeMenu, $menuTitle, $defaultLabel, $defaultTimeoutSeconds, $prepend, $append)
{
$timeoutMs = [];
$menuEntries = $prepend;
settype($menuEntries, 'array');
- if (!empty($pxeConfig)) {
- $pxe = PxeLinux::parsePxeLinux($pxeConfig);
+ if (!empty($pxeMenu)) {
+ $pxe =& $pxeMenu;
if (!empty($pxe->title)) {
$menuTitle = $pxe->title;
}
@@ -95,11 +151,10 @@ class IPxe
$timeoutMs[] = $pxe->timeoutMs;
$timeoutMs[] = $pxe->totalTimeoutMs;
foreach ($pxe->sections as $section) {
- if ($section->localBoot || preg_match('/chain.c32$/i', $section->kernel)) {
+ if ($section->localBoot || preg_match('/chain\.c32$/i', $section->kernel)) {
$menuEntries['localboot'] = 'localboot';
continue;
}
- $section->mangle();
if ($section->label === null) {
if (!$section->isHidden && !empty($section->title)) {
$menuEntries[] = $section->title;
@@ -221,7 +276,7 @@ class IPxe
'data' => json_encode([
'executable' => '/boot/default/kernel',
'initRd' => '/boot/default/initramfs-stage31',
- 'commandLine' => 'slxbase=boot/default quiet splash loglevel=5 rd.systemd.show_status=auto ${ipappend1} ${ipappend2}',
+ 'commandLine' => 'slxbase=boot/default quiet splash loglevel=5 rd.systemd.show_status=auto intel_iommu=igfx_off ${ipappend1} ${ipappend2}',
'replace' => true,
'autoUnload' => true,
'resetConsole' => true,
@@ -235,7 +290,7 @@ class IPxe
'data' => json_encode([
'executable' => '/boot/default/kernel',
'initRd' => '/boot/default/initramfs-stage31',
- 'commandLine' => 'slxbase=boot/default loglevel=7 ${ipappend1} ${ipappend2}',
+ 'commandLine' => 'slxbase=boot/default loglevel=7 intel_iommu=igfx_off ${ipappend1} ${ipappend2}',
'replace' => true,
'autoUnload' => true,
'resetConsole' => true,
@@ -314,7 +369,7 @@ class IPxe
*/
private static function pxe2BootEntry($section)
{
- if (preg_match('/(pxechain.com|pxechn.c32)$/i', $section->kernel)) {
+ if (preg_match('/(pxechain\.com|pxechn\.c32)$/i', $section->kernel)) {
// Chaining -- create script
$args = preg_split('/\s+/', $section->append);
$script = '';
diff --git a/modules-available/serversetup-bwlp/inc/pxelinux.inc.php b/modules-available/serversetup-bwlp/inc/pxelinux.inc.php
index db3dac4b..1d022fef 100644
--- a/modules-available/serversetup-bwlp/inc/pxelinux.inc.php
+++ b/modules-available/serversetup-bwlp/inc/pxelinux.inc.php
@@ -86,6 +86,9 @@ class PxeLinux
if ($section !== null) {
$menu->sections[] = $section;
}
+ foreach ($menu->sections as $section) {
+ $section->mangle();
+ }
return $menu;
}
@@ -131,6 +134,7 @@ class PxeLinux
*/
class PxeMenu
{
+
/**
* @var string menu title, shown at the top of the menu
*/
@@ -160,6 +164,40 @@ class PxeMenu
* @var PxeSection[] list of sections the menu contains
*/
public $sections = [];
+
+ public function hash($fuzzy)
+ {
+ $ctx = hash_init('md5');
+ if (!$fuzzy) {
+ hash_update($ctx, $this->title);
+ hash_update($ctx, $this->timeoutLabel);
+ }
+ hash_update($ctx, $this->timeoutMs);
+ foreach ($this->sections as $section) {
+ if ($fuzzy) {
+ hash_update($ctx, mb_strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $section->title)));
+ } else {
+ hash_update($ctx, $section->label);
+ hash_update($ctx, $section->title);
+ hash_update($ctx, $section->indent);
+ hash_update($ctx, $section->helpText);
+ hash_update($ctx, $section->isDefault);
+ hash_update($ctx, $section->hotkey);
+ }
+ hash_update($ctx, $section->kernel);
+ hash_update($ctx, $section->append);
+ hash_update($ctx, $section->ipAppend);
+ hash_update($ctx, $section->passwd);
+ hash_update($ctx, $section->isHidden);
+ hash_update($ctx, $section->isDisabled);
+ hash_update($ctx, $section->localBoot);
+ foreach ($section->initrd as $initrd) {
+ hash_update($ctx, $initrd);
+ }
+ }
+ return hash_final($ctx, false);
+ }
+
}
/**
@@ -170,6 +208,7 @@ class PxeMenu
*/
class PxeSection
{
+
/**
* @var string label used internally in PXEMENU definition to address this entry
*/
@@ -258,5 +297,6 @@ class PxeSection
$this->initrd = [];
}
}
+
}
diff --git a/modules-available/serversetup-bwlp/lang/de/messages.json b/modules-available/serversetup-bwlp/lang/de/messages.json
index de48ef0b..0772a7e4 100644
--- a/modules-available/serversetup-bwlp/lang/de/messages.json
+++ b/modules-available/serversetup-bwlp/lang/de/messages.json
@@ -1,10 +1,10 @@
{
- "boot-entry-created": "Booteintrag {{0}} erzeugt",
- "boot-entry-updated": "Booteintrag {{0}} aktualisiert",
- "bootentry-deleted": "Booteintrag gel\u00f6scht",
+ "boot-entry-created": "Men\u00fceintrag {{0}} erzeugt",
+ "boot-entry-updated": "Men\u00fceintrag {{0}} aktualisiert",
+ "bootentry-deleted": "Men\u00fceintrag gel\u00f6scht",
"error-saving-entry": "Fehler beim Speichern des Eintrags {{0}}: {{1}}",
"image-not-found": "USB-Image nicht gefunden. Generieren Sie das Bootmen\u00fc neu.",
- "invalid-boot-entry": "Ung\u00fcltiger Booteintrag: {{0}}",
+ "invalid-boot-entry": "Ung\u00fcltiger Men\u00fceintrag: {{0}}",
"invalid-ip": "Kein Interface ist auf die Adresse {{0}} konfiguriert",
"invalid-menu-id": "Ung\u00fcltige Men\u00fc-ID: {{0}}",
"localboot-invalid-method": "Ung\u00fcltige localboot-Methode: {{0}}",
@@ -14,8 +14,8 @@
"menu-deleted": "Men\u00fc gel\u00f6scht",
"menu-saved": "Men\u00fc wurde gespeichert",
"menu-set-default": "Standardmen\u00fc wurde gesetzt",
- "missing-bootentry-data": "Fehlende Daten f\u00fcr den Booteintrag",
+ "missing-bootentry-data": "Fehlende Daten f\u00fcr den Men\u00fceintrag",
"no-ip-addr-set": "Bitte w\u00e4hlen Sie die prim\u00e4re IP-Adresse des Servers",
"no-such-menu": "Men\u00fc mit ID {{0}} existiert nicht",
"unknown-bootentry-type": "Unbekannter Eintrags-Typ: {{0}}"
-}
\ No newline at end of file
+}
diff --git a/modules-available/serversetup-bwlp/lang/de/module.json b/modules-available/serversetup-bwlp/lang/de/module.json
index 31d563f0..9a8de39c 100644
--- a/modules-available/serversetup-bwlp/lang/de/module.json
+++ b/modules-available/serversetup-bwlp/lang/de/module.json
@@ -12,8 +12,8 @@
"module_name": "iPXE \/ Boot Menu",
"page_title": "PXE- und Boot-Einstellungen",
"submenu_address": "Server-Adresse",
- "submenu_bootentry": "Booteintr\u00e4ge verwalten",
+ "submenu_bootentry": "Men\u00fceintr\u00e4ge verwalten",
"submenu_download": "Downloads",
"submenu_localboot": "HDD-Boot",
"submenu_menu": "Men\u00fcs verwalten"
-}
\ No newline at end of file
+}
diff --git a/modules-available/serversetup-bwlp/lang/de/template-tags.json b/modules-available/serversetup-bwlp/lang/de/template-tags.json
index a242be5e..198a1517 100644
--- a/modules-available/serversetup-bwlp/lang/de/template-tags.json
+++ b/modules-available/serversetup-bwlp/lang/de/template-tags.json
@@ -1,8 +1,9 @@
{
"lang_active": "Aktiv",
"lang_add": "Hinzuf\u00fcgen",
- "lang_addBootentry": "Booteintrag hinzuf\u00fcgen",
+ "lang_addBootentry": "Men\u00fceintrag hinzuf\u00fcgen",
"lang_addMenu": "Men\u00fc hinzuf\u00fcgen",
+ "lang_additionalInfoLink": "Weitere Informationen",
"lang_archAgnostic": "Architekturunabh\u00e4ngig",
"lang_archBoth": "BIOS und EFI",
"lang_archSelector": "Architekturauswahl",
@@ -10,13 +11,15 @@
"lang_biosOnly": "Nur BIOS",
"lang_bootAddress": "Boot-Adresse des Servers",
"lang_bootBehavior": "Standard-Bootverhalten",
- "lang_bootEntryData": "Daten des Booteintrags",
+ "lang_bootEntryData": "Daten des Men\u00fceintrags",
"lang_bootHint": "Das Bootmen\u00fc muss nach einer \u00c4nderung der IP-Adresse neu generiert werden. In der Regel geschieht dies automatisch, der Vorgang kann in der Sektion Bootmen\u00fc allerdings auch manuell ausgel\u00f6st werden.",
"lang_bootInfo": "Hier k\u00f6nnen Anpassungen am Erscheinungsbild des Bootmen\u00fcs vorgenommen werden.",
"lang_bootMenu": "Bootmen\u00fc",
"lang_bootMenuCreate": "Bootmen\u00fc erzeugen",
- "lang_bootentryDeleteConfirm": "Sind Sie sicher, dass Sie diesen Booteintrag l\u00f6schen wollen?",
- "lang_bootentryTitle": "Booteintrag",
+ "lang_bootentryDeleteConfirm": "Sind Sie sicher, dass Sie diesen Men\u00fceintrag l\u00f6schen wollen?",
+ "lang_bootentryHead": "Men\u00fceintr\u00e4ge",
+ "lang_bootentryIntro": "Hier k\u00f6nnen Sie Men\u00fceintr\u00e4ge definieren, die sich sp\u00e4ter einem Men\u00fc zuweisen lassen. Ein Men\u00fceintrag besteht entweder aus einem zu ladenen Kernel\/Image plus optional initrd, oder aus einem iPXE-Script.",
+ "lang_bootentryTitle": "Men\u00fceintrag",
"lang_chooseIP": "Bitte w\u00e4hlen Sie die IP-Adresse, \u00fcber die der Server von den Clients zum Booten angesprochen werden soll.",
"lang_commandLine": "Command line",
"lang_count": "Anzahl",
@@ -26,7 +29,7 @@
"lang_editBuiltinWarn": "Achtung! Sie bearbeiten einen der vorgegebenen Eintr\u00e4ge! Bei einem Update k\u00f6nnten Ihre \u00c4nderungen wieder \u00fcberschrieben werden",
"lang_editMenuHead": "Men\u00fc bearbeiten",
"lang_efiOnly": "Nur EFI",
- "lang_entryChooserTitle": "Booteintrag ausw\u00e4hlen",
+ "lang_entryChooserTitle": "Men\u00fceintrag ausw\u00e4hlen",
"lang_entryId": "ID",
"lang_entryTitle": "Bezeichnung",
"lang_example": "Beispiel",
@@ -40,6 +43,7 @@
"lang_idFormatHint": "(Max. 16 Zeichen, nur a-z 0-9 - _)",
"lang_imageToLoad": "Zu ladendes Image (z.B. Kernel)",
"lang_initRd": "Zu ladendes initramfs",
+ "lang_ipxeWikiUrl": "im iPXE Wiki",
"lang_isDefault": "Standard",
"lang_listOfMenus": "Men\u00fcliste",
"lang_localBootDefault": "Standardm\u00e4\u00dfig verwendete Methode, um von Festplatte zu booten",
@@ -49,7 +53,7 @@
"lang_localHDD": "Lokale HDD",
"lang_locationCount": "Anzahl Orte",
"lang_masterPassword": "Master-Passwort",
- "lang_masterPasswordHelp": "Das Master-Passwort wird ben\u00f6tigt, um einen Booteintrag direkt am Client tempor\u00e4r durch Dr\u00fccken der Tab-Taste zu editieren. Da dies f\u00fcr Manipulation am Client genutzt werden kann, sollte diese Funktion unbedingt mit einem Passwort gesch\u00fctzt werden.",
+ "lang_masterPasswordHelp": "Das Master-Passwort wird ben\u00f6tigt, um einen Men\u00fceintrag direkt am Client tempor\u00e4r durch Dr\u00fccken der Tab-Taste zu editieren. Da dies f\u00fcr Manipulation am Client genutzt werden kann, sollte diese Funktion unbedingt mit einem Passwort gesch\u00fctzt werden.",
"lang_menuCustom": "Benutzerdefinierter Men\u00fczusatz",
"lang_menuCustomHint1": "Hier haben Sie die M\u00f6glichkeit, eigenen Men\u00fc-Code zum angezeigten PXE-Men\u00fc hinzuzuf\u00fcgen, um z.B. auf weitere PXE-Server zu verweisen. Das Format entspricht dem syslinux Men\u00fcformat.",
"lang_menuCustomHint2": "Sie k\u00f6nnen ein oder mehrere Eintr\u00e4ge erzeugen. Wenn Sie einen Eintrag erzeugen m\u00f6chten, der automatisch gestartet wird, wenn der Benutzer keine Auswahl t\u00e4tigt, vergeben Sie als",
@@ -58,16 +62,19 @@
"lang_menuDisplayTime": "Anzeigedauer des Men\u00fcs",
"lang_menuEntryOverride": "Standardeintrag \u00fcberschreiben",
"lang_menuGeneration": "Erzeugen des Bootmen\u00fcs",
+ "lang_menuListIntro": "Hier sehen Sie eine Liste aller vorhandenen Men\u00fcs, deren Zuordnung zu R\u00e4umen sowie die M\u00f6glichkeit, diese zu editieren oder l\u00f6schen. Um ein Men\u00fc einem bestimmten Raum zuzuweisen, besuchen Sie bitte den Men\u00fcpunkt \"R\u00e4ume\/Orte\".",
"lang_menuLocations": "Zugewiesene Orte",
"lang_menuTimeout": "Timeout",
"lang_menuTitle": "Men\u00fc",
"lang_moduleHeading": "iPXE \/ Boot Menu",
- "lang_newBootEntryHead": "Neuer Booteintrag",
+ "lang_newBootEntryHead": "Neuer Men\u00fceintrag",
"lang_newMenu": "Neues Men\u00fc",
"lang_none": "(keine)",
"lang_override": "\u00dcberschreiben",
"lang_pxeBuilt": "PXE-Binary gebaut",
"lang_recompileHint": "iPXE-Binaries jetzt neu kompilieren. Normalerweise wird dieser Vorgang bei \u00c4nderungen automatisch ausgef\u00fchrt. Sollten Bootprobleme auftreten, k\u00f6nnen Sie hier den Vorgang manuell ansto\u00dfen.",
+ "lang_refCount": "Referenzen",
+ "lang_referencingMenus": "Verkn\u00fcpfte Men\u00fcs",
"lang_scriptContent": "Script",
"lang_seconds": "Sekunden",
"lang_set": "Setzen",
@@ -84,4 +91,4 @@
"lang_usbImgHelpWindows": "Unter Windows muss zun\u00e4chst ein Programm besorgt werden, mit dem sich Images direkt auf einen USB-Stick schreiben lassen. Es gibt gleich mehrere kostenlose und quelloffene Programme, eines davon ist Rufus. Rufus wurde mit dem bwLehrpool-Image gestetet. Nach dem Starten des Programms ist lediglich das heruntergeladene Image zu \u00f6ffnen, sowie in der Liste der Laufwerke der richtige USB-Stick auszuw\u00e4hlen (damit Sie nicht versehentlich Daten auf dem falschen Laufwerk \u00fcberschreiben!)",
"lang_useDefaultMenu": "\u00dcbergeordnetes Men\u00fc verwenden",
"lang_useDefaultMenuEntry": "(Vorgabe des Men\u00fcs)"
-}
\ No newline at end of file
+}
diff --git a/modules-available/serversetup-bwlp/page.inc.php b/modules-available/serversetup-bwlp/page.inc.php
index 6c32cb82..bb69fecf 100644
--- a/modules-available/serversetup-bwlp/page.inc.php
+++ b/modules-available/serversetup-bwlp/page.inc.php
@@ -32,12 +32,6 @@ class Page_ServerSetup extends Page
Util::redirect('?do=Main');
}
- if (Request::any('bla') == 'blu') {
- IPxe::importLegacyMenu();
- IPxe::importPxeMenus('/srv/openslx/tftp/pxelinux.cfg');
- die('DONE');
- }
-
if (Request::any('action') === 'getimage') {
User::assertPermission("download");
$this->handleGetImage();
@@ -277,7 +271,10 @@ class Page_ServerSetup extends Page
{
$allowEdit = User::hasPermission('ipxe.bootentry.edit');
- $res = Database::simpleQuery("SELECT entryid, hotkey, title, builtin FROM serversetup_bootentry");
+ $res = Database::simpleQuery("SELECT be.entryid, be.hotkey, be.title, be.builtin, Count(*) AS refs FROM serversetup_bootentry be
+ INNER JOIN serversetup_menuentry sm USING (entryid)
+ GROUP BY be.entryid
+ ORDER BY be.title ASC");
$bootentryTable = [];
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
$bootentryTable[] = $row;
@@ -295,8 +292,13 @@ class Page_ServerSetup extends Page
// TODO Permission::addGlobalTags($perms, null, ['edit.menu', 'edit.address', 'download']);
- $res = Database::simpleQuery("SELECT m.menuid, m.title, m.isdefault, GROUP_CONCAT(l.locationid) AS locations
- FROM serversetup_menu m LEFT JOIN serversetup_menu_location l USING (menuid) GROUP BY menuid ORDER BY title");
+ $res = Database::simpleQuery("SELECT m.menuid, m.title, m.isdefault, GROUP_CONCAT(l.locationid) AS locations,
+ GROUP_CONCAT(ll.locationname SEPARATOR ', ') AS locnames
+ FROM serversetup_menu m
+ LEFT JOIN serversetup_menu_location l USING (menuid)
+ LEFT JOIN location ll USING (locationid)
+ GROUP BY menuid
+ ORDER BY title");
$menuTable = [];
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
if (empty($row['locations'])) {
@@ -351,6 +353,7 @@ class Page_ServerSetup extends Page
Message::addError('invalid-menu-id', $id);
Util::redirect('?do=serversetup&show=menu');
}
+ $highlight = Request::get('highlight', false, 'string');
if ($id !== 0 && !$this->hasMenuPermission($id, 'ipxe.menu.edit')) {
$menu['readonly'] = 'readonly';
$menu['disabled'] = 'disabled';
@@ -361,12 +364,19 @@ class Page_ServerSetup extends Page
}
$menu['timeout'] = round($menu['timeoutms'] / 1000);
- $menu['entries'] = Database::queryAll("SELECT menuentryid, entryid, hotkey, title, hidden, sortval, plainpass FROM
+ $menu['entries'] = [];
+ $res = Database::simpleQuery("SELECT menuentryid, entryid, hotkey, title, hidden, sortval, plainpass FROM
serversetup_menuentry WHERE menuid = :id ORDER BY sortval ASC", compact('id'));
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ if ($row['entryid'] == $highlight) {
+ $row['highlight'] = 'active';
+ }
+ $menu['entries'][] = $row;
+ }
$menu['keys'] = array_map(function ($item) { return ['key' => $item]; }, MenuEntry::getKeyList());
$menu['entrylist'] = Database::queryAll("SELECT entryid, title, hotkey, data FROM serversetup_bootentry ORDER BY title ASC");
foreach ($menu['entrylist'] as &$bootentry) {
- $bootentry['json'] = $bootentry['data'];
+ //$bootentry['json'] = $bootentry['data'];
$bootentry['data'] = json_decode($bootentry['data'], true);
if (array_key_exists('arch', $bootentry['data'])) {
$bootentry['data']['PCBIOS'] = array('executable' => $bootentry['data']['executable']['PCBIOS'],
@@ -386,7 +396,7 @@ class Page_ServerSetup extends Page
$bootentry['data']['arch'] = Dictionary::translateFile('template-tags','lang_archBoth', true);
}
- } else {
+ } elseif (!array_key_exists('script', $bootentry['data'])) {
$bootentry['data']['arch'] = Dictionary::translateFile('template-tags','lang_archAgnostic', true);
$bootentry['data']['archAgnostic'] = array('executable' => $bootentry['data']['executable'],
'initRd' => $bootentry['data']['initRd'],
@@ -428,8 +438,11 @@ class Page_ServerSetup extends Page
}
$entry->addFormFields($params);
$params['title'] = $row['title'];
- $params['oldentryid'] = $params['entryid'] = $row['entryid'];
+ $params['entryid'] = $row['entryid'];
$params['builtin'] = $row['builtin'];
+ $params['menus'] = Database::queryAll('SELECT m.menuid, m.title FROM serversetup_menu m
+ INNER JOIN serversetup_menuentry me ON (me.menuid = m.menuid)
+ WHERE me.entryid = :entryid', ['entryid' => $row['entryid']]);
}
Render::addTemplate('ipxe-new-boot-entry', $params);
diff --git a/modules-available/serversetup-bwlp/templates/bootentry-list.html b/modules-available/serversetup-bwlp/templates/bootentry-list.html
index 929b8c47..0cf005c5 100644
--- a/modules-available/serversetup-bwlp/templates/bootentry-list.html
+++ b/modules-available/serversetup-bwlp/templates/bootentry-list.html
@@ -1,8 +1,15 @@
+{{lang_bootentryHead}}
+
+
+ {{lang_bootentryIntro}}
+
+
{{lang_bootentryTitle}}
- Hotkey
+ {{lang_hotkey}}
+ {{lang_refCount}}
{{lang_edit}}
{{lang_delete}}
@@ -16,6 +23,9 @@
{{hotkey}}
+
+ {{refs}}
+
{{#allowEdit}}
diff --git a/modules-available/serversetup-bwlp/templates/ipxe-new-boot-entry.html b/modules-available/serversetup-bwlp/templates/ipxe-new-boot-entry.html
index fe496029..7e82b5cc 100644
--- a/modules-available/serversetup-bwlp/templates/ipxe-new-boot-entry.html
+++ b/modules-available/serversetup-bwlp/templates/ipxe-new-boot-entry.html
@@ -14,7 +14,7 @@
{{#entries}}
-
+
diff --git a/modules-available/serversetup-bwlp/templates/menu-list.html b/modules-available/serversetup-bwlp/templates/menu-list.html
index 67365a33..545f22a9 100644
--- a/modules-available/serversetup-bwlp/templates/menu-list.html
+++ b/modules-available/serversetup-bwlp/templates/menu-list.html
@@ -1,5 +1,9 @@
{{lang_listOfMenus}}
+
+ {{lang_menuListIntro}}
+
+
@@ -17,7 +21,7 @@
{{title}}
- {{locationCount}}
+ {{locationCount}}
{{^isdefault}}
@@ -37,7 +41,7 @@
{{#allowEdit}}
-
+
{{/allowEdit}}
@@ -60,6 +64,8 @@
+
+