summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2024-09-20 17:08:51 +0200
committerSimon Rettberg2024-09-20 17:08:51 +0200
commit52b3a02fb2dbb0eca3fb4effbe7c6b60a5ecf168 (patch)
treea4b4b63b19c7660b4bdf4b4e9c09466da9d9a151
parent[statistics] Ignore HDDS (block devices) that are too small (diff)
downloadslx-admin-52b3a02fb2dbb0eca3fb4effbe7c6b60a5ecf168.tar.gz
slx-admin-52b3a02fb2dbb0eca3fb4effbe7c6b60a5ecf168.tar.xz
slx-admin-52b3a02fb2dbb0eca3fb4effbe7c6b60a5ecf168.zip
[rebootcontrol/statistics] Add templates for useful remote exec commands
-rw-r--r--modules-available/rebootcontrol/inc/exectemplate.inc.php106
-rw-r--r--modules-available/rebootcontrol/inc/rebootcontrol.inc.php8
-rw-r--r--modules-available/rebootcontrol/lang/de/messages.json1
-rw-r--r--modules-available/rebootcontrol/lang/de/module.json3
-rw-r--r--modules-available/rebootcontrol/lang/de/template-tags.json1
-rw-r--r--modules-available/rebootcontrol/lang/en/messages.json1
-rw-r--r--modules-available/rebootcontrol/lang/en/module.json3
-rw-r--r--modules-available/rebootcontrol/lang/en/template-tags.json1
-rw-r--r--modules-available/rebootcontrol/pages/exec.inc.php31
-rw-r--r--modules-available/rebootcontrol/templates/exec-enter-command.html24
-rw-r--r--modules-available/statistics/page.inc.php4
-rw-r--r--modules-available/statistics/pages/machine.inc.php3
-rw-r--r--modules-available/statistics/templates/machine-main.html24
13 files changed, 193 insertions, 17 deletions
diff --git a/modules-available/rebootcontrol/inc/exectemplate.inc.php b/modules-available/rebootcontrol/inc/exectemplate.inc.php
new file mode 100644
index 00000000..483dc31f
--- /dev/null
+++ b/modules-available/rebootcontrol/inc/exectemplate.inc.php
@@ -0,0 +1,106 @@
+<?php
+declare(strict_types=1);
+
+class ExecTemplate
+{
+
+ /** @var string */
+ public $id;
+ /** @var string */
+ public $title;
+ /** @var string */
+ public $command;
+ /** @var ExecTemplateField[] */
+ public $args;
+
+ public function __construct(string $id, string $title, string $command, array $args)
+ {
+ $this->id = $id;
+ $this->title = $title;
+ $this->command = $command;
+ $this->args = $args;
+ }
+
+ public function buildFromPost(): string
+ {
+ $args = [];
+ foreach ($this->args as $arg) {
+ $args[$arg->id] = Request::post('param-' . $arg->id, '', 'string');
+ }
+ return preg_replace_callback('/%([0-9]+)([a-z]*)%/', function($out) use ($args) {
+ if (!isset($args[$out[1]])) {
+ ErrorHandler::traceError('Invalid Argument Index: ' . $out[1]);
+ }
+ $str = preg_replace('/\r\n?/', "\n", $args[$out[1]]);
+ if (strpos($out[2], 'r') === false) {
+ $str = $this->bashString($str);
+ }
+ return $str;
+ }, $this->command);
+ }
+
+ private function bashString(string $string): string
+ {
+ if (strpos($string, "'") === false) {
+ return "'$string'";
+ }
+ return "'" . str_replace("'", "'\\''", $string) . "'";
+ }
+
+ // ## STATIC ##
+
+ public static function get(string $id): ?ExecTemplate
+ {
+ // TODO: some day, maybe put these in a json file? Or DB and allow user defined ones...
+ // XXX: Add to list() too if you add something here
+ if ($id === '1') {
+ return new ExecTemplate('1', Dictionary::translateFileModule('rebootcontrol', 'module', 'exec_debug_report'),
+ 'debug_report --message %1%',
+ [new ExecTemplateField('1', Dictionary::translateFileModule('rebootcontrol', 'module', 'exec_debug_report_message'), 'string')],
+ );
+ }
+ if ($id === '2') {
+ return new ExecTemplate('2', Dictionary::translateFileModule('rebootcontrol', 'module', 'exec_systemd_plot'),
+ 'systemd-analyze plot',
+ [],
+ );
+ }
+ return null;
+ }
+
+ /**
+ * @return ExecTemplate[]
+ */
+ public static function list(): array
+ {
+ return [self::get('1'), self::get('2')];
+ }
+
+}
+
+class ExecTemplateField
+{
+
+ /** @var string */
+ private $type;
+ /** @var string */
+ public $title;
+ /** @var string */
+ public $id;
+
+ public function __construct(string $id, string $title, string $type)
+ {
+ $this->id = $id;
+ $this->title = $title;
+ $this->type = $type;
+ }
+
+ public function render(): string
+ {
+ if ($this->type === 'string') {
+ return '<input type="text" class="form-control" name="param-' . $this->id . '">';
+ }
+ return '<div>???</div>';
+ }
+
+} \ No newline at end of file
diff --git a/modules-available/rebootcontrol/inc/rebootcontrol.inc.php b/modules-available/rebootcontrol/inc/rebootcontrol.inc.php
index 107c2a50..b6ad7a16 100644
--- a/modules-available/rebootcontrol/inc/rebootcontrol.inc.php
+++ b/modules-available/rebootcontrol/inc/rebootcontrol.inc.php
@@ -446,7 +446,7 @@ class RebootControl
$subnet['iclients'] = array_slice($subnet['iclients'], 0, 3);
}
- public static function prepareExec()
+ public static function prepareExec(string $presetId = null)
{
User::assertPermission('.rebootcontrol.action.exec');
$uuids = array_values(Request::post('uuid', Request::REQUIRED, 'array'));
@@ -455,7 +455,11 @@ class RebootControl
return;
$id = mt_rand();
Session::set('exec-' . $id, $machines, 60);
- Util::redirect('?do=rebootcontrol&show=exec&what=prepare&id=' . $id);
+ $q = $id;
+ if ($presetId !== null) {
+ $q .= '&preset=' . $presetId;
+ }
+ Util::redirect('?do=rebootcontrol&show=exec&what=prepare&id=' . $q);
}
/**
diff --git a/modules-available/rebootcontrol/lang/de/messages.json b/modules-available/rebootcontrol/lang/de/messages.json
index b481d64a..9a460301 100644
--- a/modules-available/rebootcontrol/lang/de/messages.json
+++ b/modules-available/rebootcontrol/lang/de/messages.json
@@ -1,4 +1,5 @@
{
+ "exec-template-not-found": "Ung\u00fcltiges Exec-Template: {{0}}",
"invalid-cidr": "Ung\u00fcltige CIDR-Angabe: {{0}}",
"invalid-port": "Ung\u00fcltiger Port: {{0}}",
"invalid-subnet": "Ung\u00fcltiges Subnetz: {{0}}",
diff --git a/modules-available/rebootcontrol/lang/de/module.json b/modules-available/rebootcontrol/lang/de/module.json
index 2488fc81..d7e8978c 100644
--- a/modules-available/rebootcontrol/lang/de/module.json
+++ b/modules-available/rebootcontrol/lang/de/module.json
@@ -1,4 +1,7 @@
{
+ "exec_debug_report": "Fehlerbericht senden",
+ "exec_debug_report_message": "Beizuf\u00fcgender Hinweistext",
+ "exec_systemd_plot": "systemd plot erzeugen",
"jumphosts": "Sprung-Hosts",
"module_name": "Fernsteuerung \/ WakeOnLAN",
"page_title": "WakeOnLAN",
diff --git a/modules-available/rebootcontrol/lang/de/template-tags.json b/modules-available/rebootcontrol/lang/de/template-tags.json
index b54adbcd..df0a4875 100644
--- a/modules-available/rebootcontrol/lang/de/template-tags.json
+++ b/modules-available/rebootcontrol/lang/de/template-tags.json
@@ -11,6 +11,7 @@
"lang_checkingJumpHost": "Teste Sprung-Host",
"lang_client": "Client",
"lang_clientCount": "# Clients",
+ "lang_command": "Befehl",
"lang_confirmDeleteSubnet": "Dieses Subnetz wirklich l\u00f6schen?",
"lang_connecting": "Verbinde...",
"lang_directedBroadcastAddress": "Ziel-Adresse",
diff --git a/modules-available/rebootcontrol/lang/en/messages.json b/modules-available/rebootcontrol/lang/en/messages.json
index f125e944..8cfafaba 100644
--- a/modules-available/rebootcontrol/lang/en/messages.json
+++ b/modules-available/rebootcontrol/lang/en/messages.json
@@ -1,4 +1,5 @@
{
+ "exec-template-not-found": "Invalid exec template: {{0}}",
"invalid-cidr": "Invalid CIDR notion: {{0}}",
"invalid-port": "Invalid port: {{0}}",
"invalid-subnet": "Invalid subnet: {{0}}",
diff --git a/modules-available/rebootcontrol/lang/en/module.json b/modules-available/rebootcontrol/lang/en/module.json
index 1308976b..14ad50b0 100644
--- a/modules-available/rebootcontrol/lang/en/module.json
+++ b/modules-available/rebootcontrol/lang/en/module.json
@@ -1,4 +1,7 @@
{
+ "exec_debug_report": "Send debug report",
+ "exec_debug_report_message": "Message to add",
+ "exec_systemd_plot": "Generate systemd plot",
"jumphosts": "Jump hosts",
"module_name": "Remote \/ WakeOnLAN",
"page_title": "WakeOnLAN",
diff --git a/modules-available/rebootcontrol/lang/en/template-tags.json b/modules-available/rebootcontrol/lang/en/template-tags.json
index 5740b208..4f951641 100644
--- a/modules-available/rebootcontrol/lang/en/template-tags.json
+++ b/modules-available/rebootcontrol/lang/en/template-tags.json
@@ -11,6 +11,7 @@
"lang_checkingJumpHost": "Check jump host",
"lang_client": "Client",
"lang_clientCount": "# clients",
+ "lang_command": "Command",
"lang_confirmDeleteSubnet": "Delete this subnet?",
"lang_connecting": "Connecting...",
"lang_directedBroadcastAddress": "Destination address",
diff --git a/modules-available/rebootcontrol/pages/exec.inc.php b/modules-available/rebootcontrol/pages/exec.inc.php
index 6b5ea407..422f88f8 100644
--- a/modules-available/rebootcontrol/pages/exec.inc.php
+++ b/modules-available/rebootcontrol/pages/exec.inc.php
@@ -15,11 +15,19 @@ class SubPage
{
$uuids = array_values(Request::post('uuid', Request::REQUIRED, 'array'));
$machines = RebootUtils::getFilteredMachineList($uuids, 'action.exec');
- if (empty($machines))
- return;
+ if (empty($machines)) {
+ ErrorHandler::traceError('No machines');
+ }
RebootUtils::sortRunningFirst($machines);
- $script = preg_replace('/\r\n?/', "\n", Request::post('script', Request::REQUIRED, 'string'));
- $task = RebootControl::runScript($machines, $script);
+ $preset = self::presetFromRequest();
+ if ($preset !== null) {
+ $script = $preset->buildFromPost();
+ }
+ if (empty($script)) {
+ $script = preg_replace('/\r\n?/', "\n",
+ Request::post('script', Request::REQUIRED, 'string'));
+ }
+ $task = RebootControl::runScript($machines, $script, 15);
if (Taskmanager::isTask($task)) {
Util::redirect("?do=rebootcontrol&show=task&what=task&taskid=" . $task["id"]);
}
@@ -46,7 +54,20 @@ class SubPage
return;
}
Session::set('exec-' . $id, false);
- Render::addTemplate('exec-enter-command', ['clients' => $machines, 'id' => $id]);
+ $preset = self::presetFromRequest();
+ Render::addTemplate('exec-enter-command', ['clients' => $machines, 'id' => $id, 'preset' => $preset]);
+ }
+
+ private static function presetFromRequest(): ?ExecTemplate
+ {
+ $presetId = Request::any('preset', null, 'string');
+ if ($presetId === null)
+ return null;
+ $preset = ExecTemplate::get($presetId);
+ if ($preset === null) {
+ Message::addError('exec-template-not-found', $presetId);
+ }
+ return $preset;
}
public static function doAjax()
diff --git a/modules-available/rebootcontrol/templates/exec-enter-command.html b/modules-available/rebootcontrol/templates/exec-enter-command.html
index 8bf81605..09eb32f5 100644
--- a/modules-available/rebootcontrol/templates/exec-enter-command.html
+++ b/modules-available/rebootcontrol/templates/exec-enter-command.html
@@ -28,12 +28,26 @@
</tbody>
</table>
- <h3>{{lang_enterCommand}}</h3>
+ {{^preset}}
+ <h3>{{lang_enterCommand}}</h3>
+ <div>
+ <label for="script-text">{{lang_scriptOrCommand}}</label>
+ <textarea id="script-text" class="form-control" name="script" rows="10"></textarea>
+ </div>
+ {{/preset}}
+
+ {{#preset}}
+ <input type="hidden" name="preset" value="{{id}}">
+ <h3>{{title}}</h3>
+ <div class="slx-space">{{lang_command}}: <i>{{command}}</i></div>
+ {{#args}}
+ <div class="row">
+ <div class="col-md-5">{{title}}</div>
+ <div class="col-md-7">{{{render}}}</div>
+ </div>
+ {{/args}}
+ {{/preset}}
- <div>
- <label for="script-text">{{lang_scriptOrCommand}}</label>
- <textarea id="script-text" class="form-control" name="script" rows="10"></textarea>
- </div>
<div class="text-right slx-space">
<button type="submit" class="btn btn-primary" name="action" value="exec">
<span class="glyphicon glyphicon-play"></span>
diff --git a/modules-available/statistics/page.inc.php b/modules-available/statistics/page.inc.php
index 4f11e835..f07dca56 100644
--- a/modules-available/statistics/page.inc.php
+++ b/modules-available/statistics/page.inc.php
@@ -97,6 +97,10 @@ class Page_Statistics extends Page
if (Module::isAvailable('rebootcontrol')) {
RebootControl::prepareExec();
}
+ } elseif (substr($action, 0, 12) === 'exec-preset-') {
+ if (Module::isAvailable('rebootcontrol')) {
+ RebootControl::prepareExec(substr($action, 12));
+ }
}
// Make sure we don't render any content for POST requests - should be handled above and then
diff --git a/modules-available/statistics/pages/machine.inc.php b/modules-available/statistics/pages/machine.inc.php
index 34ed63da..77d9b28e 100644
--- a/modules-available/statistics/pages/machine.inc.php
+++ b/modules-available/statistics/pages/machine.inc.php
@@ -164,12 +164,13 @@ class SubPage
}
}
// Rebootcontrol
- if (Module::get('rebootcontrol') !== false) {
+ if (Module::isAvailable('rebootcontrol')) {
$client['canReboot'] = (User::hasPermission('.rebootcontrol.action.reboot', (int)$client['locationid']));
$client['canShutdown'] = (User::hasPermission('.rebootcontrol.action.shutdown', (int)$client['locationid']));
$client['canWol'] = (User::hasPermission('.rebootcontrol.action.wol', (int)$client['locationid']));
$client['canExec'] = (User::hasPermission('.rebootcontrol.action.exec', (int)$client['locationid']));
$client['rebootcontrol'] = $client['canReboot'] || $client['canShutdown'] || $client['canWol'] || $client['canExec'];
+ $client['execList'] = ExecTemplate::list();
}
// Baseconfig
if (Module::get('baseconfig') !== false
diff --git a/modules-available/statistics/templates/machine-main.html b/modules-available/statistics/templates/machine-main.html
index be32f9c7..1139d5b9 100644
--- a/modules-available/statistics/templates/machine-main.html
+++ b/modules-available/statistics/templates/machine-main.html
@@ -153,10 +153,26 @@
</button>
{{/canWol}}
{{#canExec}}
- <button type="submit" name="action" value="prepare-exec" class="btn btn-sm btn-primary btn-machine-action">
- <span class="glyphicon glyphicon-play"></span>
- {{lang_remoteExec}}
- </button>
+ <div class="btn-group">
+ <button type="submit" name="action" value="prepare-exec" class="btn btn-sm btn-primary btn-machine-action">
+ <span class="glyphicon glyphicon-play"></span>
+ {{lang_remoteExec}}
+ </button>
+ <button type="button" class="btn btn-sm btn-primary btn-machine-action dropdown-toggle"
+ data-toggle="dropdown" aria-haspopup="true">
+ <span class="caret"></span>
+ <span class="sr-only">Toggle Dropdown</span>
+ </button>
+ <div class="dropdown-menu" style="padding:0">
+ <div class="btn-group-vertical">
+ {{#execList}}
+ <button type="submit" name="action" value="exec-preset-{{id}}" class="btn btn-danger btn-machine-action">
+ {{title}}
+ </button>
+ {{/execList}}
+ </div>
+ </div>
+ </div>
{{/canExec}}
</div>
<div class="modal fade" id="reboot-confirm" tabindex="-1" role="dialog">