From 97aefcf975f23dc7cd453622da27c76a788e9bd2 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 17 Sep 2020 16:32:41 +0200 Subject: [exams/runmode/remoteaccess] Tweak baseconfig hook (runmode/format) --- .../exams/baseconfig/getconfig.inc.php | 1 + .../remoteaccess/baseconfig/getconfig.inc.php | 38 +++++++++++++--------- .../runmode/baseconfig/getconfig.inc.php | 6 ++-- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/modules-available/exams/baseconfig/getconfig.inc.php b/modules-available/exams/baseconfig/getconfig.inc.php index 10aa1d84..e7e38a33 100644 --- a/modules-available/exams/baseconfig/getconfig.inc.php +++ b/modules-available/exams/baseconfig/getconfig.inc.php @@ -22,6 +22,7 @@ $foofoo = function($machineUuid) { ConfigHolder::add('SLX_AUTOLOGIN', $autoLogin, 10000); } ConfigHolder::add('SLX_SYSTEMD_TARGET', 'exam-mode', 10000); + ConfigHolder::add('SLX_RUNMODE_MODULE', 'exams', 10000); } }; diff --git a/modules-available/remoteaccess/baseconfig/getconfig.inc.php b/modules-available/remoteaccess/baseconfig/getconfig.inc.php index 8aa6430e..4d54c183 100644 --- a/modules-available/remoteaccess/baseconfig/getconfig.inc.php +++ b/modules-available/remoteaccess/baseconfig/getconfig.inc.php @@ -1,21 +1,29 @@ $machineUuid), true); + if (is_array($res)) + return; + + // Locations from closest to furthest (order) + $locationId = ConfigHolder::get('SLX_LOCATIONS'); + if ($locationId !== false) { + $locationId = (int)$locationId; + $ret = Database::queryFirst("SELECT l.locationid FROM remoteaccess_x_location l INNER JOIN remoteaccess_group g USING (groupid) WHERE locationid = :lid AND g.active = 1", - ['lid' => $locationId], true); // TODO Remove true after next point release (2020-05-12) - if ($ret !== false) { - // TODO Properly merge - if (Property::get(RemoteAccess::PROP_TRY_VIRT_HANDOVER)) { - ConfigHolder::add("SLX_REMOTE_VNC", 'vmware virtualbox'); - } else { - ConfigHolder::add("SLX_REMOTE_VNC", 'x11vnc'); + ['lid' => $locationId], true); // TODO Remove true after next point release (2020-05-12) + if ($ret !== false) { + // TODO Properly merge + if (Property::get(RemoteAccess::PROP_TRY_VIRT_HANDOVER)) { + ConfigHolder::add("SLX_REMOTE_VNC", 'vmware virtualbox'); + } else { + ConfigHolder::add("SLX_REMOTE_VNC", 'x11vnc'); + } + ConfigHolder::add("SLX_REMOTE_HOST_ACCESS", Property::get(RemoteAccess::PROP_ALLOWED_VNC_NET)); + ConfigHolder::add('SLX_RUNMODE_MODULE', 'remoteaccess'); } - ConfigHolder::add("SLX_REMOTE_HOST_ACCESS", Property::get(RemoteAccess::PROP_ALLOWED_VNC_NET)); - ConfigHolder::add('SLX_RUNMODE_MODULE', 'remoteaccess'); } -} +})($uuid); \ No newline at end of file diff --git a/modules-available/runmode/baseconfig/getconfig.inc.php b/modules-available/runmode/baseconfig/getconfig.inc.php index 8ea2b2a6..9c36cc75 100644 --- a/modules-available/runmode/baseconfig/getconfig.inc.php +++ b/modules-available/runmode/baseconfig/getconfig.inc.php @@ -1,6 +1,6 @@ $machineUuid)); if ($res === false) @@ -17,6 +17,4 @@ $foofoo = function($machineUuid) { ConfigHolder::add('SLX_SYSTEMD_TARGET', $config->systemdDefaultTarget, 10000); } ConfigHolder::add('SLX_RUNMODE_MODULE', $res['module']); -}; - -$foofoo($uuid); \ No newline at end of file +})($uuid); -- cgit v1.2.3-55-g7522 From d1b915064e61614c3979eaad3f24c06b573a0024 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 17 Sep 2020 16:36:05 +0200 Subject: [Module] Add phpdoc --- inc/module.inc.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/inc/module.inc.php b/inc/module.inc.php index 5525c0a4..55713cd0 100644 --- a/inc/module.inc.php +++ b/inc/module.inc.php @@ -10,7 +10,12 @@ class Module * @var \Module[] */ private static $modules = false; - + + /** + * @param string $name ID/Internal name of module + * @param false $ignoreDepFail whether to return the module even if some of its dependencies failed + * @return false|Module + */ public static function get($name, $ignoreDepFail = false) { if (!isset(self::$modules[$name])) -- cgit v1.2.3-55-g7522 From e12a02856e49ce3f18bc49080dd442bed06e868e Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 21 Sep 2020 11:30:14 +0200 Subject: [statistics] Show if current runmode is different from configured one This isn't accounting for fake runmodes like "remoteaccess" or "exams", which aren't stored in the database, but actually, this might be beneficial, as you want to actually see if the clients are in this mode. --- modules-available/statistics/lang/de/template-tags.json | 3 +++ modules-available/statistics/lang/en/template-tags.json | 3 +++ modules-available/statistics/pages/list.inc.php | 13 ++++++++++++- modules-available/statistics/templates/clientlist.html | 10 +++++++++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/modules-available/statistics/lang/de/template-tags.json b/modules-available/statistics/lang/de/template-tags.json index b2d2afa3..d152390f 100644 --- a/modules-available/statistics/lang/de/template-tags.json +++ b/modules-available/statistics/lang/de/template-tags.json @@ -7,8 +7,11 @@ "lang_biosUpdate": "BIOS Update", "lang_biosUpdateLink": "Zur Herstellerseite", "lang_biosVersion": "BIOS-Version", + "lang_bootedWithoutAnyRunmode": "Ohne besonderen Betriebsmodus gestartet", + "lang_clientInDifferentRunmode": "Aktueller Betriebsmodus", "lang_clientList": "Liste ausgew\u00e4hlter Rechner", "lang_configVars": "Konfigurationsvariablen", + "lang_configuredRunMode": "Konfigurierter Betriebsmodus", "lang_cores": "Kerne", "lang_cpuCores": "CPU-Kerne", "lang_cpuModel": "CPU", diff --git a/modules-available/statistics/lang/en/template-tags.json b/modules-available/statistics/lang/en/template-tags.json index 152da3e7..6a9b0623 100644 --- a/modules-available/statistics/lang/en/template-tags.json +++ b/modules-available/statistics/lang/en/template-tags.json @@ -7,8 +7,11 @@ "lang_biosUpdate": "BIOS update", "lang_biosUpdateLink": "Go to vendor's site", "lang_biosVersion": "BIOS version", + "lang_bootedWithoutAnyRunmode": "Booted without any mode", + "lang_clientInDifferentRunmode": "Current mode", "lang_clientList": "List of selected machines", "lang_configVars": "Config Variables", + "lang_configuredRunMode": "Configured mode of operation", "lang_cores": "Cores", "lang_cpuCores": "CPU cores", "lang_cpuModel": "CPU", diff --git a/modules-available/statistics/pages/list.inc.php b/modules-available/statistics/pages/list.inc.php index 2dab152d..9f2df897 100644 --- a/modules-available/statistics/pages/list.inc.php +++ b/modules-available/statistics/pages/list.inc.php @@ -40,7 +40,8 @@ class SubPage } } $res = Database::simpleQuery("SELECT m.machineuuid, m.locationid, m.macaddr, m.clientip, m.lastseen, - m.logintime, m.state, m.currentuser, m.realcores, m.mbram, m.kvmstate, m.cpumodel, m.id44mb, m.hostname, m.notes IS NOT NULL AS hasnotes, + m.logintime, m.state, m.currentuser, m.currentrunmode, m.realcores, m.mbram, m.kvmstate, m.cpumodel, m.id44mb, + m.hostname, m.notes IS NOT NULL AS hasnotes, m.badsectors, Count(s.machineuuid) AS confvars $xtra FROM machine m LEFT JOIN setting_machine s USING (machineuuid) $join WHERE $where GROUP BY m.machineuuid", $args); @@ -101,6 +102,16 @@ class SubPage unset($row['currentuser']); } } + if ($row['state'] === 'IDLE' || $row['state'] === 'OCCUPIED') { + if ((!empty($row['currentrunmode']) || !empty($row['rmmodule'])) + && $row['currentrunmode'] !== $row['rmmodule']) { + $row['wrongRunMode'] = true; + if (!empty($row['currentrunmode'])) { + $wrongModule = Module::get($row['currentrunmode']); + $row['currentrunmode'] = $wrongModule === false ? $row['currentrunmode'] : $wrongModule->getDisplayName(); + } + } + } $row['state_' . $row['state']] = true; if ($row['locationid'] > 0) { $row['location'] = $location[$row['locationid']]; diff --git a/modules-available/statistics/templates/clientlist.html b/modules-available/statistics/templates/clientlist.html index 3d49a770..aeca368d 100644 --- a/modules-available/statistics/templates/clientlist.html +++ b/modules-available/statistics/templates/clientlist.html @@ -98,10 +98,18 @@ {{/link_details}}
{{machineuuid}}
{{#rmmodule}} -
{{lang_runMode}}: +
{{lang_configuredRunMode}}: {{moduleName}} / {{modeName}}
{{/rmmodule}} + {{#wrongRunMode}} +
+ {{lang_clientInDifferentRunmode}}: {{currentrunmode}} + {{^currentrunmode}} + {{lang_bootedWithoutAnyRunmode}} + {{/currentrunmode}} +
+ {{/wrongRunMode}} {{#currentuser}}
{{lang_user}}: -- cgit v1.2.3-55-g7522 From 147e11fdfeae4ef9817f09ae370239b741896ff5 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 22 Sep 2020 15:03:21 +0200 Subject: [serversetup-bwlp-ipxe] Re-introduce support for menuid param --- modules-available/serversetup-bwlp-ipxe/api.inc.php | 9 ++++++++- .../serversetup-bwlp-ipxe/inc/scriptbuilderipxe.inc.php | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/modules-available/serversetup-bwlp-ipxe/api.inc.php b/modules-available/serversetup-bwlp-ipxe/api.inc.php index 7575ad55..1ac885df 100644 --- a/modules-available/serversetup-bwlp-ipxe/api.inc.php +++ b/modules-available/serversetup-bwlp-ipxe/api.inc.php @@ -19,9 +19,16 @@ $entry = MenuEntry::get($entryId); $data = $builder->getMenuEntry($entry); } else { + // Get bootstrap code if required... $data = $builder->bootstrapLive(); if ($data === false) { - $menu = IPxeMenu::forClient($builder->clientIp(), $builder->uuid()); + // ...otherwise, generate normal code + $menuId = Request::get('menuid', false, 'int'); + if ($menuId !== false) { + $menu = IPxeMenu::get($menuId, true); + } else { + $menu = IPxeMenu::forClient($builder->clientIp(), $builder->uuid()); + } $data = $builder->getMenu($menu, true); } } diff --git a/modules-available/serversetup-bwlp-ipxe/inc/scriptbuilderipxe.inc.php b/modules-available/serversetup-bwlp-ipxe/inc/scriptbuilderipxe.inc.php index 3b2b847f..c8f644ab 100644 --- a/modules-available/serversetup-bwlp-ipxe/inc/scriptbuilderipxe.inc.php +++ b/modules-available/serversetup-bwlp-ipxe/inc/scriptbuilderipxe.inc.php @@ -36,7 +36,7 @@ class ScriptBuilderIpxe extends ScriptBuilderBase } unset($v); } - unset($fromQuery['menuid'], $fromQuery['entryid'], $fromQuery['special']); + unset($fromQuery['entryid'], $fromQuery['special']); if ($key !== null) { $fromQuery[$key] = $value; } -- cgit v1.2.3-55-g7522 From 59ae2573d31d3bd709453c8060c1f3cec97692b5 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 22 Sep 2020 15:04:09 +0200 Subject: [Trigger/Event] Fix minor warnings --- inc/event.inc.php | 4 ++-- inc/trigger.inc.php | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/inc/event.inc.php b/inc/event.inc.php index e5ade41b..2d916b48 100644 --- a/inc/event.inc.php +++ b/inc/event.inc.php @@ -64,7 +64,7 @@ class Event } else { $res = Taskmanager::waitComplete($ipxeId, 5000); if (Taskmanager::isFailed($res)) { - EventLog::failure('Update PXE Menu failed', $res['data']['error']); + EventLog::failure('Update PXE Menu failed', $res['data']['error'] ?? $res['data']['error'] ?? ''); $everythingFine = false; } } @@ -79,7 +79,7 @@ class Event $mountStatus = Taskmanager::waitComplete($mountId, 10000); } if ($mountId !== false && Taskmanager::isFailed($mountStatus)) { - EventLog::failure('Mounting VM store failed', $mountStatus['data']['messages']); + EventLog::failure('Mounting VM store failed', $mountStatus['data']['messages'] ?? ''); $everythingFine = false; } elseif ($mountId !== false && !Taskmanager::isFinished($mountStatus)) { // TODO: Still running - create callback diff --git a/inc/trigger.inc.php b/inc/trigger.inc.php index 134bab53..5024b907 100644 --- a/inc/trigger.inc.php +++ b/inc/trigger.inc.php @@ -98,7 +98,7 @@ class Trigger * * @param array $vmstore VM Store configuration to use. If false, read from properties * @param bool $ifLocalOnly Only execute task if the storage type is local (used for DNBD3) - * @return array|false task status of mount procedure, or false on error + * @return string|false task id of mount procedure, or false on error */ public static function mount($vmstore = false, $ifLocalOnly = false) { @@ -130,7 +130,7 @@ class Trigger }else { $opts = null; } - return Taskmanager::submit('MountVmStore', array( + $status = Taskmanager::submit('MountVmStore', array( 'address' => $addr, 'type' => 'images', 'opts' => $opts, @@ -138,6 +138,12 @@ class Trigger 'username' => $vmstore['cifsuser'], 'password' => $vmstore['cifspasswd'] )); + if (!Taskmanager::isFailed($status)) { + // In case we have a concurrent active task, this should be enough + // for the taskmanager to give us the existing id + $status = Taskmanager::waitComplete($status, 100); + } + return $status['data']['existingTask'] ?? $status['id'] ?? false; } /** -- cgit v1.2.3-55-g7522 From 0c1bfb91a90430ff95194bf1267226306aae5042 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 22 Sep 2020 15:10:04 +0200 Subject: [inc/Taskmanager] waitComplete(): Better timeout handling Sleep before first query, since we assume that we either just obtained the status object and nothing much has changed since then, or we passed in a deserialized task id from much earlier, where 100ms don't matter that much. --- inc/taskmanager.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inc/taskmanager.inc.php b/inc/taskmanager.inc.php index 85d5ee39..f7c72e04 100644 --- a/inc/taskmanager.inc.php +++ b/inc/taskmanager.inc.php @@ -140,7 +140,8 @@ class Taskmanager return false; $done = false; $deadline = microtime(true) + $timeout / 1000; - do { + while (($remaining = $deadline - microtime(true)) > 0) { + usleep(min(100000, $remaining * 100000)); $status = self::status($task); if (!isset($status['statusCode'])) break; @@ -148,8 +149,7 @@ class Taskmanager $done = true; break; } - usleep(100000); - } while (microtime(true) < $deadline); + } if ($done) { // For now we do this unconditionally, but maybe we want to keep them longer some time? self::release($task); } -- cgit v1.2.3-55-g7522 From e0e7232ec5a06b1c2ed2c925ac1dc2dc56df8eb7 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 23 Sep 2020 15:57:11 +0200 Subject: [locations] table-hover für Steffen Closes #3676 --- modules-available/locations/templates/locations.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules-available/locations/templates/locations.html b/modules-available/locations/templates/locations.html index 12d401c1..94aace8e 100644 --- a/modules-available/locations/templates/locations.html +++ b/modules-available/locations/templates/locations.html @@ -28,7 +28,7 @@
{{/mismatchMachines}} - +
{{lang_locationName}} -- cgit v1.2.3-55-g7522 From 23c87eae5805cc399c6d146da1aafd54ac8a716b Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 23 Sep 2020 15:57:37 +0200 Subject: [remoteaccess/exams] Disable screen-saver timeout for these modes --- modules-available/exams/baseconfig/getconfig.inc.php | 2 ++ modules-available/remoteaccess/baseconfig/getconfig.inc.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/modules-available/exams/baseconfig/getconfig.inc.php b/modules-available/exams/baseconfig/getconfig.inc.php index e7e38a33..120bdbff 100644 --- a/modules-available/exams/baseconfig/getconfig.inc.php +++ b/modules-available/exams/baseconfig/getconfig.inc.php @@ -23,6 +23,8 @@ $foofoo = function($machineUuid) { } ConfigHolder::add('SLX_SYSTEMD_TARGET', 'exam-mode', 10000); ConfigHolder::add('SLX_RUNMODE_MODULE', 'exams', 10000); + // No saver + ConfigHolder::add('SLX_SCREEN_SAVER_TIMEOUT', '0', 1000); } }; diff --git a/modules-available/remoteaccess/baseconfig/getconfig.inc.php b/modules-available/remoteaccess/baseconfig/getconfig.inc.php index 4d54c183..3c849b45 100644 --- a/modules-available/remoteaccess/baseconfig/getconfig.inc.php +++ b/modules-available/remoteaccess/baseconfig/getconfig.inc.php @@ -24,6 +24,8 @@ } ConfigHolder::add("SLX_REMOTE_HOST_ACCESS", Property::get(RemoteAccess::PROP_ALLOWED_VNC_NET)); ConfigHolder::add('SLX_RUNMODE_MODULE', 'remoteaccess'); + // No saver + ConfigHolder::add('SLX_SCREEN_SAVER_TIMEOUT', '0', 1000); } } })($uuid); \ No newline at end of file -- cgit v1.2.3-55-g7522 From 39354a0cc0ef32ddd432d8421dc8483002cd855b Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 28 Sep 2020 15:25:58 +0200 Subject: [dozmod] Implement deleting orphaned files from vm store This is the UI part that communicates with dmsd to show or delete all files on the vm store that don't belong to a known VM. Might be dangerous, use wisely. Closes #3321 --- modules-available/dozmod/lang/de/messages.json | 3 +- modules-available/dozmod/lang/de/permissions.json | 2 + .../dozmod/lang/de/template-tags.json | 9 +- modules-available/dozmod/lang/en/messages.json | 1 - modules-available/dozmod/lang/en/permissions.json | 2 + .../dozmod/lang/en/template-tags.json | 9 +- .../dozmod/pages/expiredimages.inc.php | 105 ++++++++----- .../dozmod/permissions/permissions.json | 6 + .../dozmod/templates/images-delete.html | 172 +++++++++++++-------- .../dozmod/templates/images-orphaned.html | 25 +++ script/slx-fixes.js | 3 +- 11 files changed, 231 insertions(+), 106 deletions(-) create mode 100644 modules-available/dozmod/templates/images-orphaned.html diff --git a/modules-available/dozmod/lang/de/messages.json b/modules-available/dozmod/lang/de/messages.json index a2d6a0ae..7eba0b2d 100644 --- a/modules-available/dozmod/lang/de/messages.json +++ b/modules-available/dozmod/lang/de/messages.json @@ -1,6 +1,5 @@ { "all-templates-reset": "Alle Templates wurden zur\u00fcckgesetzt", - "delete-images": "L\u00f6schung: {{0}}", "dozmod-error": "Fehler bei der Kommunikation mit dem bwLehrpool-Suite server: {{0}}", "images-pending-delete-exist": "Zur L\u00f6schung markierte VM-Versionen: {{0}}", "ldap-filter-created": "LDAP Filter wurde erfolgreich erstellt", @@ -33,4 +32,4 @@ "timeout": "Zeit\u00fcberschreitung", "unknown-targetid": "Target {{0}} nicht bekannt", "unknown-userid": "Unbekannter Nutzer, {{0}}" -} +} \ No newline at end of file diff --git a/modules-available/dozmod/lang/de/permissions.json b/modules-available/dozmod/lang/de/permissions.json index 8e743e5c..6159362d 100644 --- a/modules-available/dozmod/lang/de/permissions.json +++ b/modules-available/dozmod/lang/de/permissions.json @@ -8,6 +8,8 @@ "networkrules.view": "Netzwerk-Regeln einsehen.", "networkshares.save": "\u00c4nderungen an den Netzlaufwerken speichern.", "networkshares.view": "Netzlaufwerke einsehen.", + "orphaned.delete": "Verwaiste Dateien vom VM-Store l\u00f6schen.", + "orphaned.scan": "Nach Verwaisten Dateien auf VM-Store suchen.", "runscripts.save": "Startkripte erstellen\/bearbeiten.", "runscripts.view": "Startscripte auflisten.", "runtimeconfig.save": "\u00c4nderungen an der Laufzeit-Konfiguration speichern.", diff --git a/modules-available/dozmod/lang/de/template-tags.json b/modules-available/dozmod/lang/de/template-tags.json index f03fd7b6..9b2b5653 100644 --- a/modules-available/dozmod/lang/de/template-tags.json +++ b/modules-available/dozmod/lang/de/template-tags.json @@ -11,6 +11,7 @@ "lang_bwlehrpoolsuite": "bwLehrpool-Suite", "lang_canLoginOrganization": "Nutzer dieser Einrichtung k\u00f6nnen sich am Satelliten anmelden", "lang_canLoginUser": "Nutzer kann sich am Satelliten anmelden", + "lang_confirmDeleteOrphanedFiles": "Sind Sie sicher, dass Sie alle aufgelisteten Dateien unwiderruflich vom VM-Store l\u00f6schen wollen?", "lang_createTime": "Erstellt", "lang_currentFilter": "Aktueller Filter", "lang_defaultImagePermissionAdmin": "Administrieren", @@ -21,6 +22,7 @@ "lang_defaultLecturePermissions": "F\u00fcr Veranstaltungen", "lang_defaultPermissions": "Standardberechtigungen", "lang_delButton": "Gew\u00e4hlte VMs endg\u00fcltig l\u00f6schen", + "lang_deleteExpiredHeading": "Zu l\u00f6schende VM-Versionen", "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.", @@ -33,11 +35,11 @@ "lang_emailNotifications": "EMail-Benachrichtigungen aktiviert", "lang_error": "Fehler", "lang_event": "Ereignis", + "lang_fileName": "Dateiname", "lang_fileSize": "Dateigr\u00f6\u00dfe", "lang_followingPlaceholdersUnused": "Folgende Platzhalter m\u00fcssen im Template verwendet werden", "lang_hasNewer": "Neuere Version existiert", "lang_hash": "Hash", - "lang_heading": "Zu l\u00f6schende VM-Versionen", "lang_hidden": "Versteckt", "lang_host": "Host", "lang_image": "VM", @@ -77,6 +79,9 @@ "lang_normal": "Normal", "lang_organization": "Einrichtung", "lang_organizationListHeader": "Nutzungsrechte f\u00fcr den Satelliten festlegen", + "lang_orphanDeleteButton": "Dateien l\u00f6schen", + "lang_orphanedFilesDesc": "Hier aufgelistete Dateien geh\u00f6ren zu keiner aus der Datenbank bekannten VM. Sollten Sie sich sicher sein, dass diese Dateien nicht anderweitig verwendet werden, oder h\u00e4ndisch auf dem VM-Store abgelegt wurden, k\u00f6nnen Sie diese Dateien l\u00f6schen, um Speicherplatz zu gewinnen. Wenn Sie sich nicht sicher sind, untersuchen Sie die Situation auf dem VM-Store h\u00e4ndisch.", + "lang_orphanedFilesHeading": "Verwaiste Images und Dateien auf dem VM-Store", "lang_os": "Betriebssystem", "lang_owner": "Besitzer", "lang_passwordCleartextHint": "Bitte beachten Sie, dass ein hier explizit angegebenes Passwort im Klartext an das Poolsystem \u00fcbergeben wird. Sie sollten also nur dedizierte Funktionsaccounts nutzen, die keinen Zugriff auf weitere Systeme erm\u00f6glichen.", @@ -93,6 +98,7 @@ "lang_runScriptDeleteConfirmation": "Skript wirklich l\u00f6schen?", "lang_runtimeConfig": "Laufzeit-Konfiguration", "lang_runtimeConfigLimits": "Beschr\u00e4nkungen", + "lang_scanButton": "VM-Store durchsuchen", "lang_scriptContent": "Skriptinhalt", "lang_scriptExtension": "Dateinamenerweiterung", "lang_scriptExtensionHead": "Erweiterung", @@ -121,6 +127,7 @@ "lang_sslExplicit": "Explizites SSL (\"STARTTLS\")", "lang_sslImplicit": "Implizites SSL", "lang_sslNone": "Kein SSL", + "lang_status": "Status", "lang_superUser": "Ist SuperUser (darf alle Veranstaltungen und VMs bearbeiten\/l\u00f6schen)", "lang_system": "System", "lang_target": "Ziel", diff --git a/modules-available/dozmod/lang/en/messages.json b/modules-available/dozmod/lang/en/messages.json index 84677402..1b46339b 100644 --- a/modules-available/dozmod/lang/en/messages.json +++ b/modules-available/dozmod/lang/en/messages.json @@ -1,6 +1,5 @@ { "all-templates-reset": "All templates have been reset", - "delete-images": "Delete: {{0}}", "dozmod-error": "Error communicating with the bwLehrpool-Suite server: {{0}}", "images-pending-delete-exist": "VMs marked for deletion: {{0}}", "ldap-filter-created": "LDAP filter was successfully created", diff --git a/modules-available/dozmod/lang/en/permissions.json b/modules-available/dozmod/lang/en/permissions.json index 3d82bdda..479b150b 100644 --- a/modules-available/dozmod/lang/en/permissions.json +++ b/modules-available/dozmod/lang/en/permissions.json @@ -8,6 +8,8 @@ "networkrules.view": "View network rules.", "networkshares.save": "Save network drives.", "networkshares.view": "View network drives.", + "orphaned.delete": "Delete orphaned files from VM store.", + "orphaned.scan": "Scan for orphaned files on VM store.", "runscripts.save": "Save startup scripts.", "runscripts.view": "View startup scripts.", "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 1ab25a06..425ceefa 100644 --- a/modules-available/dozmod/lang/en/template-tags.json +++ b/modules-available/dozmod/lang/en/template-tags.json @@ -11,6 +11,7 @@ "lang_bwlehrpoolsuite": "bwLehrpool-Suite", "lang_canLoginOrganization": "Users from this organization can login", "lang_canLoginUser": "This user can login", + "lang_confirmDeleteOrphanedFiles": "Are you sure you want to permanently delete the files listed below?", "lang_createTime": "Created", "lang_currentFilter": "Current filter", "lang_defaultImagePermissionAdmin": "Administrate", @@ -21,6 +22,7 @@ "lang_defaultLecturePermissions": "For lectures", "lang_defaultPermissions": "Default permissions", "lang_delButton": "Permanently delete selected images", + "lang_deleteExpiredHeading": "Images marked for deletion", "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.)", @@ -33,11 +35,11 @@ "lang_emailNotifications": "E-Mail notifications enabled", "lang_error": "Error", "lang_event": "Event", + "lang_fileName": "File name", "lang_fileSize": "File size", "lang_followingPlaceholdersUnused": "The following placeholders are not being used", "lang_hasNewer": "newer version exists", "lang_hash": "Hash", - "lang_heading": "Images Marked for Deletion", "lang_hidden": "Hidden", "lang_host": "Host", "lang_image": "VM", @@ -77,6 +79,9 @@ "lang_normal": "Normal", "lang_organization": "Organization", "lang_organizationListHeader": "Set access permissions for organizations", + "lang_orphanDeleteButton": "Delete files", + "lang_orphanedFilesDesc": "Files listed here could not be matched to any VM from the database. If you're sure that these files aren't used for anything else (e.g. shared VM store), you can delete these files to free up space. If you're not sure, leave them alone or manually examine the situation on the file system.", + "lang_orphanedFilesHeading": "Orphaned files on VM store", "lang_os": "Operating System", "lang_owner": "Owner", "lang_passwordCleartextHint": "Please not that explicitly provided credentials will be passed in clear text. You should only use dedicated accounts that don't give access to anything else than the desired network share(s).", @@ -93,6 +98,7 @@ "lang_runScriptDeleteConfirmation": "Do you want to delete this run-script?", "lang_runtimeConfig": "Limits and Defaults", "lang_runtimeConfigLimits": "Limitations", + "lang_scanButton": "Scan VM store", "lang_scriptContent": "Script content", "lang_scriptExtension": "Script extension", "lang_scriptExtensionHead": "Extension", @@ -121,6 +127,7 @@ "lang_sslExplicit": "Explicit SSL (\"STARTTLS\")", "lang_sslImplicit": "Implicit SSL", "lang_sslNone": "No SSL", + "lang_status": "Status", "lang_superUser": "Is super user (can edit\/delete all lectures and VMs)", "lang_system": "System", "lang_target": "Target", diff --git a/modules-available/dozmod/pages/expiredimages.inc.php b/modules-available/dozmod/pages/expiredimages.inc.php index 2b5a2274..ffd7b026 100644 --- a/modules-available/dozmod/pages/expiredimages.inc.php +++ b/modules-available/dozmod/pages/expiredimages.inc.php @@ -5,40 +5,7 @@ class SubPage public static function doPreprocess() { - $action = Request::post('action', false, 'string'); - if ($action === 'delimages') { - if (User::hasPermission("expiredimages.delete")) { - $result = self::handleDeleteImages(); - if (!empty($result)) { - Message::addInfo('delete-images', $result); - } - Util::redirect('?do=DozMod'); - } - } - } - - private static function handleDeleteImages() - { - $images = Request::post('images', false); - if (is_array($images)) { - foreach ($images as $image => $val) { - if (strtolower($val) !== 'on') - continue; - Database::exec("UPDATE sat.imageversion SET deletestate = 'WANT_DELETE'" - . " WHERE deletestate = 'SHOULD_DELETE' AND imageversionid = :imageversionid", array( - 'imageversionid' => $image - )); - } - if (!empty($images)) { - $ret = Download::asStringPost('http://127.0.0.1:9080/do/delete-images', false, 10, $code); - if ($code == 999) { - $ret .= "\nConnection to DMSD failed."; - } - return $ret; - } - } - return false; } private static function loadExpiredImages() @@ -80,7 +47,9 @@ class SubPage if (empty($expiredImages)) { Message::addSuccess('no-expired-images'); } else { - Render::addTemplate('images-delete', array('images' => $expiredImages, 'allowedDelete' => User::hasPermission("expiredimages.delete"))); + $data = ['images' => $expiredImages]; + Permission::addGlobalTags($data['perm'], null, ['expiredimages.delete', 'orphaned.scan']); + Render::addTemplate('images-delete', $data); } } @@ -88,10 +57,72 @@ class SubPage { $action = Request::post('action'); if ($action === 'delimages') { - User::assertPermission("expiredimages.delete"); - die(self::handleDeleteImages()); + self::handleDeleteImages(); + } elseif ($action === 'orphaned') { + self::handleOrphaned(); + } else { + echo 'Huh?'; + } + } + + private static function handleDeleteImages() + { + User::assertPermission("expiredimages.delete"); + $images = Request::post('images', false); + $result = false; + if (is_array($images)) { + foreach ($images as $image => $val) { + if (strtolower($val) !== 'on') + continue; + Database::exec("UPDATE sat.imageversion SET deletestate = 'WANT_DELETE'" + . " WHERE deletestate = 'SHOULD_DELETE' AND imageversionid = :imageversionid", array( + 'imageversionid' => $image + )); + } + if (!empty($images)) { + $result = Download::asStringPost('http://127.0.0.1:9080/do/delete-images', false, 10, $code); + if ($code == 999) { + $result .= "\nConnection to DMSD failed."; + } + } + } + if (!empty($result)) { + echo $result; + } + } + + private static function handleOrphaned() + { + if (Request::post('delete', 0, 'int') !== 0) { + User::assertPermission("orphaned.delete"); + $action = 'delete'; + } else { + User::assertPermission("orphaned.scan"); + $action = 'scan'; + } + // Talk to dmsd + $result = Download::asStringPost('http://127.0.0.1:9080/do/scan-orphaned-files', ['action' => $action], + 10, $code); + if ($code == 999) { + $result = '
' + . $result . ' - Connection to DMSD failed.
'; + } else { + $json = json_decode($result, true); + if (is_array($json)) { + $result = []; + $showDelete = false; + foreach ($json as $k => $v) { + $result[] = ['file' => $k, 'status' => $v]; + if ($v === 'EXISTS') { + $showDelete = true; + } + } + $data = ['files' => $result, 'show_delete' => $showDelete]; + Permission::addGlobalTags($data['perm'], null, ['orphaned.delete']); + $result = Render::parse('images-orphaned', $data); + } } - die('Huh?'); + echo $result; } } diff --git a/modules-available/dozmod/permissions/permissions.json b/modules-available/dozmod/permissions/permissions.json index c8958089..12d0acd3 100644 --- a/modules-available/dozmod/permissions/permissions.json +++ b/modules-available/dozmod/permissions/permissions.json @@ -2,6 +2,12 @@ "expiredimages.delete": { "location-aware": false }, + "orphaned.scan": { + "location-aware": false + }, + "orphaned.delete": { + "location-aware": false + }, "actionlog.view": { "location-aware": false }, diff --git a/modules-available/dozmod/templates/images-delete.html b/modules-available/dozmod/templates/images-delete.html index 78690426..9d61559f 100644 --- a/modules-available/dozmod/templates/images-delete.html +++ b/modules-available/dozmod/templates/images-delete.html @@ -2,96 +2,142 @@
- {{lang_heading}} + {{lang_deleteExpiredHeading}}

{{lang_description_delete_images}}

-
+ - - - - - - - - + + + + + + + + - {{#images}} - - - - - - - - - {{/images}} + {{#images}} + + + + + + + + + {{/images}}
{{lang_image}}{{lang_version}}{{lang_owner}}{{lang_size}} -
- - - -
-
{{lang_image}}{{lang_version}}{{lang_owner}}{{lang_size}} +
+ + + +
+
{{displayname}}
{{imageversionid}}
{{version}}{{lastname}}, {{firstname}}{{filesize}} -
- - -
-
{{displayname}}
{{imageversionid}} +
{{version}}{{lastname}}, {{firstname}}{{filesize}} +
+ + +
+
- +
- diff --git a/modules-available/dozmod/templates/images-orphaned.html b/modules-available/dozmod/templates/images-orphaned.html new file mode 100644 index 00000000..d1b74a42 --- /dev/null +++ b/modules-available/dozmod/templates/images-orphaned.html @@ -0,0 +1,25 @@ + + + + + + + + + {{#files}} + + + + + {{/files}} + +
{{lang_fileName}}{{lang_status}}
{{file}}{{status}}
+ +{{#show_delete}} + +{{/show_delete}} \ No newline at end of file diff --git a/script/slx-fixes.js b/script/slx-fixes.js index 992ca337..a06761e4 100644 --- a/script/slx-fixes.js +++ b/script/slx-fixes.js @@ -61,6 +61,7 @@ $(document).ready(function() { var $title, $body, $button, $modal = null, $cache = {}; slxModalConfirmHandler = function (e) { e.preventDefault(); + e.stopImmediatePropagation(); var $this = $(this); if ($modal === null) { $modal = $('