summaryrefslogtreecommitdiffstats
path: root/modules-available/backup
diff options
context:
space:
mode:
authorSimon Rettberg2016-05-03 19:03:09 +0200
committerSimon Rettberg2016-05-03 19:03:09 +0200
commit50404f3b23b7fd6aeae4c9d2f6df0ea25e984e66 (patch)
tree05e99fdffa696434960d7c77966c0bc36d6339e8 /modules-available/backup
parentSecond half of merge.... (diff)
downloadslx-admin-50404f3b23b7fd6aeae4c9d2f6df0ea25e984e66.tar.gz
slx-admin-50404f3b23b7fd6aeae4c9d2f6df0ea25e984e66.tar.xz
slx-admin-50404f3b23b7fd6aeae4c9d2f6df0ea25e984e66.zip
WIP
Diffstat (limited to 'modules-available/backup')
-rw-r--r--modules-available/backup/config.json4
-rw-r--r--modules-available/backup/lang/de/module.json4
-rw-r--r--modules-available/backup/lang/de/templates/_page.json14
-rw-r--r--modules-available/backup/lang/de/templates/restore.json8
-rw-r--r--modules-available/backup/lang/en/module.json14
-rw-r--r--modules-available/backup/lang/en/templates/_page.json14
-rw-r--r--modules-available/backup/lang/en/templates/restore.json8
-rw-r--r--modules-available/backup/lang/pt/module.json14
-rw-r--r--modules-available/backup/page.inc.php164
-rw-r--r--modules-available/backup/templates/_page.html41
-rw-r--r--modules-available/backup/templates/restore.html62
11 files changed, 347 insertions, 0 deletions
diff --git a/modules-available/backup/config.json b/modules-available/backup/config.json
new file mode 100644
index 00000000..6c189b63
--- /dev/null
+++ b/modules-available/backup/config.json
@@ -0,0 +1,4 @@
+{
+ "category":"main.content",
+ "enabled":"true"
+}
diff --git a/modules-available/backup/lang/de/module.json b/modules-available/backup/lang/de/module.json
new file mode 100644
index 00000000..a0dbdf27
--- /dev/null
+++ b/modules-available/backup/lang/de/module.json
@@ -0,0 +1,4 @@
+{
+ "module_name": "Sichern/Wiederherstellen",
+ "page_title": "Sichern und wiederherstellen"
+}
diff --git a/modules-available/backup/lang/de/templates/_page.json b/modules-available/backup/lang/de/templates/_page.json
new file mode 100644
index 00000000..5e3efea2
--- /dev/null
+++ b/modules-available/backup/lang/de/templates/_page.json
@@ -0,0 +1,14 @@
+{
+ "lang_backup": "Sichern",
+ "lang_backupDescription": "Hier k\u00f6nnen Sie die Konfiguration des Satellitenservers sichern. Dies beinhaltet die Datenbank \u00fcber alle Virtuellen Maschinen, Veranstaltungen, Authentifizerungsmodule, Passw\u00f6rter, Proxies, den konfigurierten VM-Store sowie weitere Konfiguration des MiniLinux.\r\nDie Festplattenabbilder der Virtuellen Maschinen auf dem VM-Store werden hierbei nicht gesichert. Eventuelle Backups des Stores m\u00fcssen separat durchgef\u00fchrt werden.",
+ "lang_backupRestore": "Sichern und Wiederherstellen",
+ "lang_browseForFile": "Durchsuchen",
+ "lang_download": "Herunterladen",
+ "lang_dozmodExplanation": "Die Datenbank des Dozentenmoduls wiederherstellen. Dazu geh\u00f6ren die Metadaten der Virtuellen Maschinen, die Veranstaltungen, etc. Bitte beachten Sie, dass hierzu auf dem konfigurierten VM-Store die passenden VM-Abbilder vorliegen m\u00fcssen, da diese extern gespeichert werden. Wenn sich der Servername oder die -adresse ge\u00e4ndert haben stellen Sie bitte sicher, dass die relativen Pfade innerhalb des Netzlaufwerks gleich geblieben sind. Ansonsten werden die wiederhergestellten VMs nicht verwendbar sein.",
+ "lang_restore": "Hochladen",
+ "lang_restoreDescription": "Hier k\u00f6nnen Sie ein Backup der Konfiguration wieder einspielen. Bitte beachten Sie, dass der Server dabei neu gestartet wird, daher sollten Sie dies m\u00f6glichst durchf\u00fchren, wenn das System nicht genutzt wird, und keine Dozenten Veranstaltungen oder Virtuelle Labore erstellen oder hoch-\/herunterladen. Bitte beachten Sie, dass dabei auch das urspr\u00fcngliche Passwort der Weboberfl\u00e4che wiederhergestellt wird.",
+ "lang_restoreDozmodConfig": "Dozentenmodul-Konfiguration wiederherstellen",
+ "lang_restoreSystemConfig": "Systemkonfiguration wiederherstellen",
+ "lang_selectFile": "Bitte w\u00e4hlen Sie ein Backup-Archiv",
+ "lang_systemExplanation": "Die Grundkonfiguration des Satelliten wiederherstellen: Authentifizierungmethode, Passw\u00f6rter, Proxies, VM-Storage, etc.\r\nACHTUNG: Wenn Sie ein Backup von vor WS15\/16 einspielen (Backup-Format vor Version 10), wird die Systemkonfiguration in jedem Fall wiederhergestellt, auch wenn Sie diesen Haken nicht setzen."
+} \ No newline at end of file
diff --git a/modules-available/backup/lang/de/templates/restore.json b/modules-available/backup/lang/de/templates/restore.json
new file mode 100644
index 00000000..6b3a7cdd
--- /dev/null
+++ b/modules-available/backup/lang/de/templates/restore.json
@@ -0,0 +1,8 @@
+{
+ "lang_backup": "Sichern...",
+ "lang_reboot": "Systemneustart",
+ "lang_restoreConfig": "Konfiguration wiederherstellen",
+ "lang_restoreFailed": "Wiederherstellung der Konfiguration fehlgeschlagen.",
+ "lang_stopping": "Stoppe",
+ "lang_waitReboot": "Warte auf Reboot."
+} \ No newline at end of file
diff --git a/modules-available/backup/lang/en/module.json b/modules-available/backup/lang/en/module.json
new file mode 100644
index 00000000..c9379ffd
--- /dev/null
+++ b/modules-available/backup/lang/en/module.json
@@ -0,0 +1,14 @@
+{
+ "lang_backup": "Backup",
+ "lang_backupDescription": "Here you can backup the complete configuration of this satellite server.",
+ "lang_backupRestore": "Backup and restore",
+ "lang_download": "Download",
+ "lang_file": "File",
+ "lang_reboot": "System reboot",
+ "lang_restore": "Upload",
+ "lang_restoreConfig": "Restore config",
+ "lang_restoreDescription": "Here you can restore a configuration backup. Please note that this will reboot the server, so it is advised to do this while nobody is using the system. Please note that this will also restore the password for the web interface that was active when the configuration backup was created.",
+ "lang_restoreFailed": "Restoring configuration failed.",
+ "lang_stopping": "Stopping",
+ "module_name": "Backup"
+} \ No newline at end of file
diff --git a/modules-available/backup/lang/en/templates/_page.json b/modules-available/backup/lang/en/templates/_page.json
new file mode 100644
index 00000000..799c6168
--- /dev/null
+++ b/modules-available/backup/lang/en/templates/_page.json
@@ -0,0 +1,14 @@
+{
+ "lang_backup": "Backup",
+ "lang_backupDescription": "Here you can backup the complete configuration of this satellite server. This includes lecture and virtual machine meta data. The HDD images of the virtual machines on the vm store are not included in this backup, because of their size. If desired, the store needs to be backed up manually.",
+ "lang_backupRestore": "Backup and restore",
+ "lang_browseForFile": "Browse",
+ "lang_download": "Download",
+ "lang_dozmodExplanation": "This restores all the virtual machine and lecture meta data created using the \"Dozentenmodul\". Please make sure the VM-storage configured still contains all the VM-Images associated with the virtual machines. If the location of the storage changed, make sure the relative pathes on the share are still the same, otherwise the virtual machines won't be usable.",
+ "lang_restore": "Upload",
+ "lang_restoreDescription": "Here you can restore a configuration backup. Please note that this will reboot the server, so it is advised to do this while nobody is using the system. Please note that this will also restore the password for the web interface that was active when the configuration backup was created.",
+ "lang_restoreDozmodConfig": "Restore Dozentenmodul config",
+ "lang_restoreSystemConfig": "Restore system config",
+ "lang_selectFile": "Please select a backup archive",
+ "lang_systemExplanation": "Restore basic configuration like authentication method, passwords, vm storage location, proxy config, etc. WARNING: If you restore a configuration backup that was made before WS15\/16 (backup format version <10), the system configuration will be restored regardless of this check mark."
+} \ No newline at end of file
diff --git a/modules-available/backup/lang/en/templates/restore.json b/modules-available/backup/lang/en/templates/restore.json
new file mode 100644
index 00000000..5a5f6f64
--- /dev/null
+++ b/modules-available/backup/lang/en/templates/restore.json
@@ -0,0 +1,8 @@
+{
+ "lang_backup": "Backup...",
+ "lang_reboot": "System reboot",
+ "lang_restoreConfig": "Restore config",
+ "lang_restoreFailed": "Restoring configuration failed.",
+ "lang_stopping": "Stopping",
+ "lang_waitReboot": "Waiting for reboot."
+} \ No newline at end of file
diff --git a/modules-available/backup/lang/pt/module.json b/modules-available/backup/lang/pt/module.json
new file mode 100644
index 00000000..5077cbfa
--- /dev/null
+++ b/modules-available/backup/lang/pt/module.json
@@ -0,0 +1,14 @@
+{
+ "lang_backup": "Backup",
+ "lang_backupDescription": "Aqui voc\u00ea pode fazer um backup completo da configura\u00e7\u00e3o deste server.",
+ "lang_backupRestore": "Backup e Recupera\u00e7\u00e3o",
+ "lang_download": "Baixar",
+ "lang_file": "Arquivo",
+ "lang_reboot": "Reinicializar Sistema",
+ "lang_restore": "Carregar",
+ "lang_restoreConfig": "Recuperar Configura\u00e7\u00e3o",
+ "lang_restoreDescription": "Aqui voc\u00ea pode recuperar um backup de configura\u00e7\u00e3o. Por favor note que isso ir\u00e1 reinicializar o servidor, portanto \u00e9 recomendado faz\u00ea-lo quando ningu\u00e9m estiver utilizando o sistema. Por favor note que isso tamb\u00e9m ir\u00e1 recuperar a senha da interface web que estava ativa quando a configura\u00e7\u00e3o de backup foi criada.",
+ "lang_restoreFailed": "Recupera\u00e7\u00e3o da configura\u00e7\u00e3o falhou",
+ "lang_stopping": "Parando",
+ "module_name": "Backup"
+} \ No newline at end of file
diff --git a/modules-available/backup/page.inc.php b/modules-available/backup/page.inc.php
new file mode 100644
index 00000000..4095f875
--- /dev/null
+++ b/modules-available/backup/page.inc.php
@@ -0,0 +1,164 @@
+<?php
+
+class Page_Backup extends Page
+{
+
+ private $action = false;
+ private $templateData = array();
+
+ protected function doPreprocess()
+ {
+ User::load();
+ if (!User::hasPermission('superadmin')) {
+ Message::addError('no-permission');
+ Util::redirect('?do=Main');
+ }
+ $this->action = Request::post('action');
+ if ($this->action === 'backup') {
+ $this->backup();
+ } elseif ($this->action === 'restore') {
+ $this->restore();
+ }
+ }
+
+ protected function doRender()
+ {
+ Render::setTitle(Dictionary::translate('lang_titleBackup'));
+ if ($this->action === 'restore') {
+ Render::addTemplate('restore', $this->templateData);
+ } else {
+ Render::addScriptBottom('fileselect');
+ Render::addTemplate('_page');
+ }
+ }
+
+ private function backup()
+ {
+ $task = Taskmanager::submit('BackupRestore', array('mode' => 'backup'));
+ if (!isset($task['id'])) {
+ Message::addError('backup-failed');
+ Util::redirect('?do=Backup');
+ }
+ $task = Taskmanager::waitComplete($task, 30000);
+ if (!Taskmanager::isFinished($task) || !isset($task['data']['backupFile'])) {
+ Taskmanager::addErrorMessage($task);
+ Util::redirect('?do=Backup');
+ }
+ while ((@ob_get_level()) > 0)
+ @ob_end_clean();
+ $fh = @fopen($task['data']['backupFile'], 'rb');
+ if ($fh === false) {
+ Message::addError('error-read', $task['data']['backupFile']);
+ Util::redirect('?do=Backup');
+ }
+ Header('Content-Type: application/octet-stream', true);
+ Header('Content-Disposition: attachment; filename=' . 'satellite-backup_v' . Database::getExpectedSchemaVersion() . '_' . date('Y.m.d-H.i.s') . '.tgz');
+ Header('Content-Length: ' . @filesize($task['data']['backupFile']));
+ while (!feof($fh)) {
+ $data = fread($fh, 16000);
+ if ($data === false) {
+ EventLog::failure('Could not stream system backup to browser - backup corrupted!');
+ die("\r\n\nDOWNLOAD INTERRUPTED!\n");
+ }
+ echo $data;
+ @ob_flush();
+ @flush();
+ }
+ @fclose($fh);
+ @unlink($task['data']['backupFile']);
+ die();
+ }
+
+ private function restore()
+ {
+ if (!isset($_FILES['backupfile'])) {
+ Message::addError('missing-file');
+ Util::redirect('?do=Backup');
+ }
+ if ($_FILES['backupfile']['error'] != UPLOAD_ERR_OK) {
+ Message::addError('upload-failed', Util::uploadErrorString($_FILES['backupfile']['error']));
+ Util::redirect('?do=Backup');
+ }
+ $tempfile = '/tmp/bwlp-' . mt_rand(1, 100000) . '-' . crc32($_SERVER['REMOTE_ADDR']) . '.tgz';
+ if (!move_uploaded_file($_FILES['backupfile']['tmp_name'], $tempfile)) {
+ Message::addError('error-write', $tempfile);
+ Util::redirect('?do=Backup');
+ }
+ // Got uploaded file, now shut down all the daemons etc.
+ $parent = Trigger::stopDaemons(null, $this->templateData);
+ // Unmount store
+ $task = Taskmanager::submit('MountVmStore', array(
+ 'address' => 'null',
+ 'type' => 'images',
+ 'parentTask' => $parent,
+ 'failOnParentFail' => false
+ ));
+ if (isset($task['id'])) {
+ $this->templateData['mountid'] = $task['id'];
+ $parent = $task['id'];
+ }
+ EventLog::info('Creating backup, v' . Database::getExpectedSchemaVersion() . ' on ' . Property::getServerIp());
+ // Finally run restore
+ $task = Taskmanager::submit('BackupRestore', array(
+ 'mode' => 'restore',
+ 'backupFile' => $tempfile,
+ 'parentTask' => $parent,
+ 'failOnParentFail' => false,
+ 'restoreOpenslx' => Request::post('restore_openslx', 'off') === 'on',
+ 'restoreDozmod' => Request::post('restore_dozmod', 'off') === 'on',
+ ));
+ if (isset($task['id'])) {
+ $this->templateData['restoreid'] = $task['id'];
+ $parent = $task['id'];
+ TaskmanagerCallback::addCallback($task, 'dbRestored');
+ }
+ // Wait a bit
+ $task = Taskmanager::submit('SleepTask', array(
+ 'seconds' => 3,
+ 'parentTask' => $parent,
+ 'failOnParentFail' => false
+ ));
+ if (isset($task['id']))
+ $parent = $task['id'];
+ // Reboot
+ $task = Taskmanager::submit('Reboot', array(
+ 'parentTask' => $parent,
+ 'failOnParentFail' => false
+ ));
+ // Leave this comment so the i18n scanner finds it:
+ // Message::addSuccess('restore-done');
+ if (isset($task['id']))
+ $this->templateData['rebootid'] = $task['id'];
+ }
+ private function stopDaemons($parent)
+ {
+ $task = Taskmanager::submit('SyncdaemonLauncher', array(
+ 'operation' => 'stop',
+ 'parentTask' => $parent,
+ 'failOnParentFail' => false
+ ));
+ if (isset($task['id'])) {
+ $this->templateData['syncid'] = $task['id'];
+ $parent = $task['id'];
+ }
+ $task = Taskmanager::submit('DozmodLauncher', array(
+ 'operation' => 'stop',
+ 'parentTask' => $parent,
+ 'failOnParentFail' => false
+ ));
+ if (isset($task['id'])) {
+ $this->templateData['dmsdid'] = $task['id'];
+ $parent = $task['id'];
+ }
+ $task = Taskmanager::submit('LdadpLauncher', array(
+ 'ids' => array(),
+ 'parentTask' => $parent,
+ 'failOnParentFail' => false
+ ));
+ if (isset($task['id'])) {
+ $this->templateData['ldadpid'] = $task['id'];
+ $parent = $task['id'];
+ }
+ return $parent;
+ }
+}
diff --git a/modules-available/backup/templates/_page.html b/modules-available/backup/templates/_page.html
new file mode 100644
index 00000000..47b5a174
--- /dev/null
+++ b/modules-available/backup/templates/_page.html
@@ -0,0 +1,41 @@
+<h1>{{lang_backupRestore}}</h1>
+
+<form action="?do=Backup" method="post">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="action" value="backup">
+ <div class="panel panel-default">
+ <div class="panel-heading">{{lang_backup}}</div>
+ <div class="panel-body">
+ <p>{{lang_backupDescription}}</p>
+ <button class="btn btn-primary" type="submit">{{lang_download}}</button>
+ </div>
+ </div>
+</form>
+
+<form action="?do=Backup" method="post" enctype="multipart/form-data">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="action" value="restore">
+ <div class="panel panel-default">
+ <div class="panel-heading">{{lang_restore}}</div>
+ <div class="panel-body">
+ <p>{{lang_restoreDescription}}</p>
+ <div class="input-group upload-ex">
+ <input type="text" class="form-control" readonly placeholder="{{lang_selectFile}}">
+ <span class="input-group-btn">
+ <span class="btn btn-default btn-file">
+ {{lang_browseForFile}}&hellip; <input type="file" name="backupfile">
+ </span>
+ </span>
+ </div>
+ <div>
+ <label><input type="checkbox" name="restore_openslx" checked="checked"> {{lang_restoreSystemConfig}}</label>
+ <p><i>{{lang_systemExplanation}}</i></p>
+ </div>
+ <div>
+ <label><input type="checkbox" name="restore_dozmod" checked="checked"> {{lang_restoreDozmodConfig}}</label>
+ <p><i>{{lang_dozmodExplanation}}</i></p>
+ </div>
+ <button class="btn btn-primary" type="submit">{{lang_restore}}</button>
+ </div>
+ </div>
+</form> \ No newline at end of file
diff --git a/modules-available/backup/templates/restore.html b/modules-available/backup/templates/restore.html
new file mode 100644
index 00000000..4494a993
--- /dev/null
+++ b/modules-available/backup/templates/restore.html
@@ -0,0 +1,62 @@
+<div class="panel panel-default">
+ <div class="panel-heading">{{lang_backup}}</div>
+ <div class="panel-body">
+ <div id="zeug">
+ <div data-tm-id="{{syncid}}" data-tm-log="messages">{{lang_stopping}} syncdaemon</div>
+ <div data-tm-id="{{dmsdid}}" data-tm-log="messages">{{lang_stopping}} dmsd</div>
+ <div data-tm-id="{{ldadpid}}" data-tm-log="messages">{{lang_stopping}} ldadp</div>
+ <div data-tm-id="{{mountid}}" data-tm-log="messages">{{lang_stopping}} vmstore</div>
+ <div data-tm-id="{{restoreid}}" data-tm-log="messages" data-tm-callback="restoreCb">{{lang_restoreConfig}}</div>
+ <div data-tm-id="{{rebootid}}" data-tm-log="messages">{{lang_reboot}}</div>
+ </div>
+ <div id="restorefailed" class="alert alert-danger" style="display:none">
+ {{lang_restoreFailed}}
+ </div>
+ <div id="waiting" style="display:none">
+ <span id="dots"></span>
+ </div>
+ </div>
+</div>
+
+<script type="text/javascript">
+ function restoreCb(task)
+ {
+ if (!task || !task.statusCode)
+ return;
+ if (task.statusCode === 'TASK_ERROR') {
+ $('#restorefailed').show('slow');
+ }
+ if (task.statusCode === 'TASK_ERROR' || task.statusCode === 'TASK_FINISHED') {
+ startRebootPoll();
+ }
+ }
+
+ function startRebootPoll()
+ {
+ $('#waiting').show();
+ $('#waiting').prepend('<span class="glyphicon glyphicon-refresh slx-rotation"></span>');
+ $('#dots').text('{{lang_waitReboot}}');
+ slxDotInterval = setInterval(function() { $('#dots').text($('#dots').text() + '..'); }, 3000);
+ setTimeout('rebootPoll()', 10000);
+ }
+
+ function rebootPoll()
+ {
+ if (slxDotInterval !== false) {
+ clearInterval(slxDotInterval);
+ slxDotInterval = false;
+ }
+ $('#dots').text($('#dots').text() + '..');
+ slxTimeoutId = setTimeout('rebootPoll()', 3500);
+ $.ajax({url: "index.php?do=Main", timeout: 3000}).success(function(data, textStatus, jqXHR) {
+ if (textStatus !== "success" && textStatus !== "notmodified")
+ return;
+ if (data.indexOf('Status: DB running') === -1)
+ return;
+ clearTimeout(slxTimeoutId);
+ setTimeout(function() {
+ window.location.replace("index.php?do=Main&message[]=success%7Crestore-done");
+ }, 3500);
+ });
+ }
+</script>