summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2018-04-25 16:46:18 +0200
committerSimon Rettberg2018-04-25 16:46:18 +0200
commit7d4b41dc7e85b4f5f249c61db11ae27d53144c9c (patch)
tree5e36609f07cb851a5bbbecda66c42b0e51f76002
parent[locations] Fix machine counting (diff)
downloadslx-admin-7d4b41dc7e85b4f5f249c61db11ae27d53144c9c.tar.gz
slx-admin-7d4b41dc7e85b4f5f249c61db11ae27d53144c9c.tar.xz
slx-admin-7d4b41dc7e85b4f5f249c61db11ae27d53144c9c.zip
[rebootcontrol] Nicer status list; list of all running jobs
-rw-r--r--modules-available/rebootcontrol/inc/rebootcontrol.inc.php65
-rw-r--r--modules-available/rebootcontrol/inc/rebootqueries.inc.php4
-rw-r--r--modules-available/rebootcontrol/lang/de/template-tags.json6
-rw-r--r--modules-available/rebootcontrol/lang/en/template-tags.json6
-rw-r--r--modules-available/rebootcontrol/page.inc.php48
-rw-r--r--modules-available/rebootcontrol/templates/_page.html44
-rw-r--r--modules-available/rebootcontrol/templates/status.html26
-rw-r--r--modules-available/rebootcontrol/templates/task-list.html33
8 files changed, 186 insertions, 46 deletions
diff --git a/modules-available/rebootcontrol/inc/rebootcontrol.inc.php b/modules-available/rebootcontrol/inc/rebootcontrol.inc.php
index 789552cd..1024b036 100644
--- a/modules-available/rebootcontrol/inc/rebootcontrol.inc.php
+++ b/modules-available/rebootcontrol/inc/rebootcontrol.inc.php
@@ -3,28 +3,83 @@
class RebootControl
{
+ const KEY_TASKLIST = 'rebootcontrol.tasklist';
+
+ const REBOOT = 'REBOOT';
+ const KEXEC_REBOOT = 'KEXEC_REBOOT';
+ const SHUTDOWN = 'SHUTDOWN';
+
/**
* @param string[] $uuids List of machineuuids to reboot
+ * @param bool $kexec whether to trigger kexec-reboot instead of full BIOS cycle
* @return false|array task struct for the reboot job
*/
- public static function reboot($uuids)
+ public static function reboot($uuids, $kexec = false)
{
$list = RebootQueries::getMachinesByUuid($uuids);
if (empty($list))
return false;
- return self::execute($list, false, 0, 0);
+ return self::execute($list, $kexec ? RebootControl::KEXEC_REBOOT : RebootControl::REBOOT, 0, 0);
}
- public static function execute($list, $shutdown, $minutes, $locationId)
+ /**
+ * @param array $list list of clients containing each keys 'machineuuid' and 'clientip'
+ * @param string $mode reboot mode: RebootControl::REBOOT ::KEXEC_REBOOT or ::SHUTDOWN
+ * @param int $minutes delay in minutes for action
+ * @param int $locationId meta data only: locationId of clients
+ * @return array|false the task, or false if it could not be started
+ */
+ public static function execute($list, $mode, $minutes, $locationId)
{
- return Taskmanager::submit("RemoteReboot", array(
+ $task = Taskmanager::submit("RemoteReboot", array(
"clients" => $list,
- "shutdown" => $shutdown,
+ "mode" => $mode,
"minutes" => $minutes,
"locationId" => $locationId,
"sshkey" => SSHKey::getPrivateKey(),
"port" => 9922, // Hard-coded, must match mgmt-sshd module
));
+ if (!Taskmanager::isFailed($task)) {
+ Property::addToList(RebootControl::KEY_TASKLIST, $locationId . '/' . $task["id"], 60 * 24);
+ }
+ return $task;
+ }
+
+ /**
+ * @param int[]|null $locations filter by these locations
+ * @return array list of active tasks for reboots/shutdowns.
+ */
+ public static function getActiveTasks($locations = null)
+ {
+ if (is_array($locations) && in_array(0,$locations)) {
+ $locations = null;
+ }
+ $list = Property::getList(RebootControl::KEY_TASKLIST);
+ $return = [];
+ foreach ($list as $entry) {
+ $p = explode('/', $entry, 2);
+ if (count($p) !== 2) {
+ Property::removeFromList(RebootControl::KEY_TASKLIST, $entry);
+ continue;
+ }
+ if (is_array($locations) && !in_array($p[0], $locations)) // Ignore
+ continue;
+ $id = $p[1];
+ $task = Taskmanager::status($id);
+ if ($task === false) {
+ Property::removeFromList(RebootControl::KEY_TASKLIST, $entry);
+ continue;
+ }
+ $return[] = [
+ 'taskId' => $task['id'],
+ 'locationId' => $task['data']['locationId'],
+ 'time' => $task['data']['time'],
+ 'mode' => $task['data']['mode'],
+ 'clientCount' => count($task['data']['clients']),
+ 'status' => $task['statusCode'],
+ ];
+ }
+ return $return;
}
} \ No newline at end of file
diff --git a/modules-available/rebootcontrol/inc/rebootqueries.inc.php b/modules-available/rebootcontrol/inc/rebootqueries.inc.php
index 525a9e58..063b36e4 100644
--- a/modules-available/rebootcontrol/inc/rebootqueries.inc.php
+++ b/modules-available/rebootcontrol/inc/rebootqueries.inc.php
@@ -44,13 +44,13 @@ class RebootQueries
/**
* Get machines by list of UUIDs
* @param string[] $list list of system UUIDs
- * @return array list of machines with machineuuid, clientip, state and locationid
+ * @return array list of machines with machineuuid, hostname, clientip, state and locationid
*/
public static function getMachinesByUuid($list)
{
if (empty($list))
return array();
- $res = Database::simpleQuery("SELECT machineuuid, clientip, state, locationid FROM machine
+ $res = Database::simpleQuery("SELECT machineuuid, hostname, clientip, state, locationid FROM machine
WHERE machineuuid IN (:list)", compact('list'));
return $res->fetchAll(PDO::FETCH_ASSOC);
}
diff --git a/modules-available/rebootcontrol/lang/de/template-tags.json b/modules-available/rebootcontrol/lang/de/template-tags.json
index eccc8738..c678ef88 100644
--- a/modules-available/rebootcontrol/lang/de/template-tags.json
+++ b/modules-available/rebootcontrol/lang/de/template-tags.json
@@ -1,13 +1,17 @@
{
+ "lang_activeTasks": "Laufende Jobs",
"lang_authFail": "Authentifizierung fehlgeschlagen",
"lang_client": "Client",
+ "lang_clientCount": "# Clients",
"lang_confirmNewKeypair": "Wirklich neues Schl\u00fcsselpaar erzeugen?",
"lang_connecting": "Verbinde...",
"lang_error": "Nicht erreichbar",
"lang_genNew": "Neues Schl\u00fcsselpaar generieren",
"lang_ip": "IP",
+ "lang_kexecRebootCheck": "Schneller Reboot direkt in bwLehrpool",
"lang_location": "Standort",
"lang_minutes": " Minuten",
+ "lang_mode": "Modus",
"lang_newKeypairExplanation": "Sie k\u00f6nnen ein neues Schl\u00fcsselpaar erzeugen lassen. In diesem Fall wird das alte Schl\u00fcsselpaar verworfen, sodass alle zum jetzigen Zeitpunkt bereits gestarteten Rechner nicht mehr aus der Ferne bedient werden k\u00f6nnen, bis diese manuell neugestartet wurden.",
"lang_off": "Aus",
"lang_on": "An",
@@ -18,6 +22,7 @@
"lang_rebootButton": "Neustarten",
"lang_rebootCheck": "Wollen Sie die ausgew\u00e4hlten Rechner wirklich neustarten?",
"lang_rebootControl": "Reboot Control",
+ "lang_rebootIn": "Neustart in:",
"lang_rebooting": "Neustart...",
"lang_selectall": "Alle ausw\u00e4hlen",
"lang_selected": "Ausgew\u00e4hlt",
@@ -29,5 +34,6 @@
"lang_shutdownCheck": "Wollen Sie die ausgew\u00e4hlten Rechner wirklich herunterfahren?",
"lang_shutdownIn": "Herunterfahren in: ",
"lang_status": "Status",
+ "lang_time": "Zeit",
"lang_unselectall": "Alle abw\u00e4hlen"
} \ No newline at end of file
diff --git a/modules-available/rebootcontrol/lang/en/template-tags.json b/modules-available/rebootcontrol/lang/en/template-tags.json
index c2346044..c64014ff 100644
--- a/modules-available/rebootcontrol/lang/en/template-tags.json
+++ b/modules-available/rebootcontrol/lang/en/template-tags.json
@@ -1,13 +1,17 @@
{
+ "lang_activeTasks": "Active tasks",
"lang_authFail": "Authentication failed",
"lang_client": "Client",
+ "lang_clientCount": "# clients",
"lang_confirmNewKeypair": "Really create new key pair?",
"lang_connecting": "Connecting...",
"lang_error": "Not available",
"lang_genNew": "Generate new keypair",
"lang_ip": "IP",
+ "lang_kexecRebootCheck": "Quick reboot straight to bwLehrpool (kexec)",
"lang_location": "Location",
"lang_minutes": " Minutes",
+ "lang_mode": "Mode",
"lang_newKeypairExplanation": "You can create a new keypair, which will replace the old one. Please note that after doing so, you cannot poweroff or reboot clients that are already running, since they still use the old key. They have to be rebooted manually first.",
"lang_off": "Off",
"lang_on": "On",
@@ -18,6 +22,7 @@
"lang_rebootButton": "Reboot",
"lang_rebootCheck": "Do you really want to reboot the selected clients?",
"lang_rebootControl": "Reboot Control",
+ "lang_rebootIn": "Reboot in:",
"lang_rebooting": "Rebooting...",
"lang_selectall": "Select all",
"lang_selected": "Selected",
@@ -29,5 +34,6 @@
"lang_shutdownCheck": "Do you really want to shut down the selected clients?",
"lang_shutdownIn": "Shutdown in: ",
"lang_status": "Status",
+ "lang_time": "Time",
"lang_unselectall": "Unselect all"
} \ No newline at end of file
diff --git a/modules-available/rebootcontrol/page.inc.php b/modules-available/rebootcontrol/page.inc.php
index 675c94f8..3a438504 100644
--- a/modules-available/rebootcontrol/page.inc.php
+++ b/modules-available/rebootcontrol/page.inc.php
@@ -27,7 +27,6 @@ class Page_RebootControl extends Page
Message::addError('no-clients-selected');
Util::redirect();
}
- $minutes = Request::post('minutes', 0, 'int');
$actualClients = RebootQueries::getMachinesByUuid($requestedClients);
if (count($actualClients) !== count($requestedClients)) {
@@ -56,8 +55,22 @@ class Page_RebootControl extends Page
return 0;
return $a ? -1 : 1;
});
- $task = RebootControl::execute($actualClients, $this->action === 'shutdown', $minutes, $locationId);
- Util::redirect("?do=rebootcontrol&taskid=".$task["id"]);
+ if ($this->action === 'shutdown') {
+ $mode = 'SHUTDOWN';
+ $minutes = Request::post('s-minutes', 0, 'int');
+ } elseif (Request::any('quick', false, 'string') === 'on') {
+ $mode = 'KEXEC_REBOOT';
+ $minutes = Request::post('r-minutes', 0, 'int');
+ } else {
+ $mode = 'REBOOT';
+ $minutes = Request::post('r-minutes', 0, 'int');
+ }
+ $task = RebootControl::execute($actualClients, $mode, $minutes, $locationId);
+ if (Taskmanager::isTask($task)) {
+ Util::redirect("?do=rebootcontrol&taskid=" . $task["id"]);
+ } else {
+ Util::redirect("?do=rebootcontrol");
+ }
}
}
@@ -71,15 +84,22 @@ class Page_RebootControl extends Page
if ($this->action === 'show') {
$data = [];
- $taskId = Request::get("taskid");
+ $task = Request::get("taskid", false, 'string');
+ if ($task !== false) {
+ $task = Taskmanager::status($task);
+ }
- if ($taskId && Taskmanager::isTask($taskId)) {
- $task = Taskmanager::status($taskId);
- $data['taskId'] = $taskId;
+ if (Taskmanager::isTask($task)) {
+
+ $data['taskId'] = $task['id'];
$data['locationId'] = $task['data']['locationId'];
$data['locationName'] = Location::getName($task['data']['locationId']);
- $data['clients'] = $task['data']['clients'];
+ $uuids = array_map(function($entry) {
+ return $entry['machineuuid'];
+ }, $task['data']['clients']);
+ $data['clients'] = RebootQueries::getMachinesByUuid($uuids);
Render::addTemplate('status', $data);
+
} else {
//location you want to see, default are "not assigned" clients
@@ -103,6 +123,8 @@ class Page_RebootControl extends Page
foreach ($data['locations'] as &$loc) {
if (!in_array($loc["locationid"], $allowedLocs)) {
$loc["disabled"] = "disabled";
+ } elseif ($loc["locationid"] == $requestedLocation) {
+ $data['location'] = $loc['locationname'];
}
}
// Always show public key (it's public, isn't it?)
@@ -121,6 +143,16 @@ class Page_RebootControl extends Page
Render::addTemplate('_page', $data);
}
+ // Append list of active reboot/shutdown tasks
+ $active = RebootControl::getActiveTasks($allowedLocs);
+ if (!empty($active)) {
+ foreach ($active as &$entry) {
+ $entry['locationName'] = Location::getName($entry['locationId']);
+ }
+ unset($entry);
+ Render::addTemplate('task-list', ['list' => $active]);
+ }
+
}
}
}
diff --git a/modules-available/rebootcontrol/templates/_page.html b/modules-available/rebootcontrol/templates/_page.html
index 82f82b02..a124e165 100644
--- a/modules-available/rebootcontrol/templates/_page.html
+++ b/modules-available/rebootcontrol/templates/_page.html
@@ -1,4 +1,6 @@
-<form id="tableDataForm" method="post" action="?do=rebootcontrol" class="form-inline">
+<h3>{{location}}</h3>
+
+<form method="post" action="?do=rebootcontrol" class="form-inline">
<input type="hidden" name="token" value="{{token}}">
<div class="row">
<div class="col-md-12">
@@ -45,9 +47,7 @@
</div>
</div>
-
<!-- Modals -->
-
<div class ="modal fade" id="rebootModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
@@ -56,17 +56,27 @@
<h4 class="modal-title" id="myModalLabel">{{lang_rebootButton}}</h4>
</div>
<div class="modal-body">
- {{lang_rebootCheck}}
+ <div>{{lang_rebootCheck}}</div>
+ <div>{{lang_rebootIn}} <input name="r-minutes" title="{{lang_shutdownIn}}" type="number" value="0" min="0" pattern="\d+"> {{lang_minutes}}</div>
+ <div>
+ <div class="checkbox checkbox-inline">
+ <input name="quick" type="checkbox" value="on" id="rb-quick">
+ <label for="rb-quick">{{lang_kexecRebootCheck}}</label>
+ </div>
+ </div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
- <button type="submit" {{perms.action.reboot.disabled}} name="action" value="reboot" class="btn btn-warning"><span class="glyphicon glyphicon-repeat"></span> {{lang_reboot}}</button>
+ <button type="submit" {{perms.action.reboot.disabled}} name="action" value="reboot" class="btn btn-warning">
+ <span class="glyphicon glyphicon-repeat"></span>
+ {{lang_reboot}}
+ </button>
</div>
</div>
</div>
</div>
- <div class ="modal fade" id="shutdownModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+ <div class ="modal fade" id="shutdownModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel2">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
@@ -74,12 +84,15 @@
<h4 class="modal-title" id="myModalLabel2">{{lang_shutdownButton}}</h4>
</div>
<div class="modal-body">
- {{lang_shutdownCheck}}
- {{lang_shutdownIn}} <input id="shutdownTimer" name="minutes" title="{{lang_shutdownIn}}" type="number" value="0" min="0" pattern="\d+"> {{lang_minutes}}
+ <div>{{lang_shutdownCheck}}</div>
+ {{lang_shutdownIn}} <input name="s-minutes" title="{{lang_shutdownIn}}" type="number" value="0" min="0" pattern="\d+"> {{lang_minutes}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
- <button type="submit" {{perms.action.shutdown.disabled}} name="action" value="shutdown" class="btn btn-danger"><span class="glyphicon glyphicon-off"></span> {{lang_shutdownButton}}</button>
+ <button type="submit" {{perms.action.shutdown.disabled}} name="action" value="shutdown" class="btn btn-danger">
+ <span class="glyphicon glyphicon-off"></span>
+ {{lang_shutdownButton}}
+ </button>
</div>
</div>
</div>
@@ -168,17 +181,4 @@
}
}
- function generateNewKeypair() {
- if (!confirm('{{lang_confirmNewKeypair}}'))
- return;
- $.ajax({
- url: '?do=rebootcontrol',
- type: 'POST',
- data: { action: "generateNewKeypair", token: TOKEN },
- success: function(value) {
- $('#pubKey').text(value);
- }
- });
- }
-
</script> \ No newline at end of file
diff --git a/modules-available/rebootcontrol/templates/status.html b/modules-available/rebootcontrol/templates/status.html
index c2fdab46..c05b2fad 100644
--- a/modules-available/rebootcontrol/templates/status.html
+++ b/modules-available/rebootcontrol/templates/status.html
@@ -7,8 +7,6 @@
</form>
</div>
-<div data-tm-id="{{taskId}}" data-tm-log="error" data-tm-callback="updateStatus"></div>
-
<div>
<table class="table table-hover stupidtable" id="dataTable">
<thead>
@@ -24,7 +22,7 @@
<tbody>
{{#clients}}
<tr>
- <td>{{machineuuid}}</td>
+ <td>{{hostname}}{{^hostname}}{{machineuuid}}{{/hostname}}</td>
<td>{{clientip}}</td>
<td id="status-{{machineuuid}}"></td>
</tr>
@@ -33,6 +31,8 @@
</table>
</div>
+<div data-tm-id="{{taskId}}" data-tm-log="error" data-tm-callback="updateStatus"></div>
+
<script type="application/javascript">
statusStrings = {
"CONNECTING" : "{{lang_connecting}}",
@@ -50,12 +50,20 @@
return;
var clientStatus = task.data.clientStatus;
for (var uuid in clientStatus) {
- if (clientStatus.hasOwnProperty(uuid)) {
- var shutdownTime = ' ';
- if (clientStatus[uuid] === 'SHUTDOWN_AT' || clientStatus[uuid] === 'REBOOT_AT') {
- shutdownTime += task.data.time;
- }
- $("#status-" + uuid).text(statusStrings[clientStatus[uuid]] + shutdownTime);
+ if (!clientStatus.hasOwnProperty(uuid))
+ continue;
+ var $s = $("#status-" + uuid);
+ var status = clientStatus[uuid];
+ if ($s.data('state') === status)
+ continue;
+ $s.data('state', status);
+ var text = statusStrings[status];
+ if (status === 'SHUTDOWN_AT' || status === 'REBOOT_AT') {
+ text += ' ' + task.data.time;
+ }
+ $s.text(text);
+ if (status === 'CONNECTING' || status === 'REBOOTING') {
+ $s.append('<span class="glyphicon glyphicon-hourglass"></span>');
}
}
}
diff --git a/modules-available/rebootcontrol/templates/task-list.html b/modules-available/rebootcontrol/templates/task-list.html
new file mode 100644
index 00000000..063ba949
--- /dev/null
+++ b/modules-available/rebootcontrol/templates/task-list.html
@@ -0,0 +1,33 @@
+<h3>{{lang_activeTasks}}</h3>
+<table class="table">
+ <thead>
+ <tr>
+ <th>{{lang_mode}}</th>
+ <th>{{lang_location}}</th>
+ <th>{{lang_time}}</th>
+ <th>{{lang_clientCount}}</th>
+ <th>{{lang_status}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#list}}
+ <tr>
+ <td>
+ <a href="?do=rebootcontrol&amp;taskid={{taskId}}">{{mode}}</a>
+ </td>
+ <td>
+ {{locationName}}
+ </td>
+ <td>
+ {{time}}
+ </td>
+ <td>
+ {{clientCount}}
+ </td>
+ <td>
+ {{status}}
+ </td>
+ </tr>
+ {{/list}}
+ </tbody>
+</table> \ No newline at end of file