From 9db03926a80a910aa9ef338a5ad1d2328e6e6cb7 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 2 Mar 2023 13:47:49 +0100 Subject: [backup] Add UI for monthly automatic backup + password support --- modules-available/backup/hooks/cron.inc.php | 38 +++++++++++++++ modules-available/backup/inc/backuprestore.inc.php | 13 +++++ modules-available/backup/page.inc.php | 57 ++++++++++++++++++---- modules-available/backup/templates/_page.html | 50 +++++++++++++++++-- 4 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 modules-available/backup/hooks/cron.inc.php create mode 100644 modules-available/backup/inc/backuprestore.inc.php (limited to 'modules-available/backup') diff --git a/modules-available/backup/hooks/cron.inc.php b/modules-available/backup/hooks/cron.inc.php new file mode 100644 index 00000000..529a3feb --- /dev/null +++ b/modules-available/backup/hooks/cron.inc.php @@ -0,0 +1,38 @@ += 5) + return; + $mode = Property::get(BackupRestore::PROP_AUTO_BACKUP_MODE, BackupRestore::BACKUP_MODE_OFF); + if ($mode === BackupRestore::BACKUP_MODE_OFF) + return; + // DO IT + $password = trim(Property::get(BackupRestore::PROP_AUTO_BACKUP_PASS, '')); + if (empty($password)) { + $password = null; + } + if ($mode === BackupRestore::BACKUP_MODE_VMSTORE) { + $destination = '/srv/openslx/nfs/auto_backups/'; + } else { + $destination = '/root/auto_backups/'; + } + $destination .= 'sat-' . Property::getServerIp() . '-' . date('Y-m-d'); + $task = Taskmanager::submit('BackupRestore', [ + 'mode' => 'backup', + 'password' => $password, + 'destination' => $destination, + ]); + if (!isset($task['id'])) { + EventLog::failure("Could not create automatic backup, Taskmanager down"); + return; + } + $task = Taskmanager::waitComplete($task, 60000); + if (!Taskmanager::isFinished($task) || !isset($task['data']['backupFile'])) { + EventLog::failure("Creating backup failed", print_r($task, true)); + return; + } + if (!is_readable($task['data']['backupFile'])) { + EventLog::failure("Backup file '{$task['data']['backupFile']}' is not readable"); + return; + } +})(); \ No newline at end of file diff --git a/modules-available/backup/inc/backuprestore.inc.php b/modules-available/backup/inc/backuprestore.inc.php new file mode 100644 index 00000000..c34c86a2 --- /dev/null +++ b/modules-available/backup/inc/backuprestore.inc.php @@ -0,0 +1,13 @@ +action === 'restore') { User::assertPermission("restore"); $this->restore(); + } elseif ($this->action === 'config') { + User::assertPermission("config"); + $this->config(); } User::assertPermission('*'); } @@ -31,27 +33,40 @@ class Page_Backup extends Page if ($this->action === 'restore') { // TODO: We're in post mode, redirect with all the taskids first... Render::addTemplate('restore', $this->templateData); } else { - $lastBackup = (int)Property::get(self::LAST_BACKUP_PROP, 0); + $lastBackup = (int)Property::get(BackupRestore::PROP_LAST_BACKUP, 0); if ($lastBackup === 0) { $lastBackup = false; } else { $lastBackup = date('d.m.Y', $lastBackup); } - $params = ['last_backup' => $lastBackup]; - Permission::addGlobalTags($params['perms'], NULL, ['create', 'restore']); + $params = [ + 'last_backup' => $lastBackup, + 'autoBackupEnabled_checked' => Property::get(BackupRestore::PROP_AUTO_BACKUP_MODE, BackupRestore::BACKUP_MODE_OFF) + != BackupRestore::BACKUP_MODE_OFF ? 'checked' : '', + 'autoBackupPw' => Property::get(BackupRestore::PROP_AUTO_BACKUP_PASS, ''), + ]; + Permission::addGlobalTags($params['perms'], NULL, ['create', 'restore', 'config']); Render::addTemplate('_page', $params); } } private function backup() { - $task = Taskmanager::submit('BackupRestore', array('mode' => 'backup')); + $password = trim(Request::post('passwd', '', 'string')); + if (empty($password)) { + $password = null; + } + $task = Taskmanager::submit('BackupRestore', [ + 'mode' => 'backup', + 'password' => $password, + ]); if (!isset($task['id'])) { Message::addError('backup-failed'); Util::redirect('?do=Backup'); } - $task = Taskmanager::waitComplete($task, 30000); + $task = Taskmanager::waitComplete($task, 60000); if (!Taskmanager::isFinished($task) || !isset($task['data']['backupFile'])) { + file_put_contents('/tmp/bwlp-backup-error-' . time() . '.txt', json_encode($task['data'])); Taskmanager::addErrorMessage($task); Util::redirect('?do=Backup'); } @@ -62,8 +77,12 @@ class Page_Backup extends Page Message::addError('main.error-read', $task['data']['backupFile']); Util::redirect('?do=Backup'); } + $userFn = 'satellite-backup_' . Property::getServerIp() . '_' . date('Y.m.d-H.i.s') . '.tgz'; + if ($password !== null) { + $userFn .= '.aes'; + } Header('Content-Type: application/octet-stream', true); - Header('Content-Disposition: attachment; filename=' . 'satellite-backup_' . Property::getServerIp() . '_' . date('Y.m.d-H.i.s') . '.tgz'); + Header('Content-Disposition: attachment; filename=' . $userFn); Header('Content-Length: ' . @filesize($task['data']['backupFile'])); while (!feof($fh)) { $data = fread($fh, 16000); @@ -77,7 +96,7 @@ class Page_Backup extends Page } @fclose($fh); @unlink($task['data']['backupFile']); - Property::set(self::LAST_BACKUP_PROP, time()); + Property::set(BackupRestore::PROP_LAST_BACKUP, time()); die(); } @@ -110,9 +129,14 @@ class Page_Backup extends Page $parent = $task['id']; } EventLog::info('Creating backup on ' . Property::getServerIp()); + $password = trim(Request::post('passwd', '', 'string')); + if (empty($password)) { + $password = null; + } // Finally run restore $task = Taskmanager::submit('BackupRestore', array( 'mode' => 'restore', + 'password' => $password, 'backupFile' => $tempfile, 'parentTask' => $parent, 'failOnParentFail' => false, @@ -143,4 +167,17 @@ class Page_Backup extends Page $this->templateData['rebootid'] = $task['id']; } + private function config() + { + $password = trim(Request::post('passwd', '', 'string')); + if (empty($password)) { + $password = null; + } + $mode = Request::post('auto-backup-enabled', 0, 'int') + ? BackupRestore::BACKUP_MODE_VMSTORE : BackupRestore::BACKUP_MODE_OFF; + Property::set(BackupRestore::PROP_AUTO_BACKUP_MODE, $mode); + Property::set(BackupRestore::PROP_AUTO_BACKUP_PASS, $password); + Util::redirect('?do=backup'); + } + } diff --git a/modules-available/backup/templates/_page.html b/modules-available/backup/templates/_page.html index 3e57c033..52dd7e72 100644 --- a/modules-available/backup/templates/_page.html +++ b/modules-available/backup/templates/_page.html @@ -7,13 +7,20 @@
{{lang_backup}}

{{lang_backupDescription}}

+
+ + +
+ {{lang_backupPasswordHint}}

{{lang_lastBackup}}: {{^last_backup}}{{lang_unknown}}{{/last_backup}} {{last_backup}}

@@ -26,22 +33,28 @@
{{lang_restore}}

{{lang_restoreDescription}}

+
- + {{lang_browseForFile}}…
-
+
+ + +
+

{{lang_systemExplanation}}

-
+
@@ -53,7 +66,34 @@ {{lang_runningUploads}}: ??, {{lang_runningDownloads}}: ??
- + +
+
+ + +
+ + +
+
{{lang_autoBackupHeading}}
+
+

{{lang_autoBackupText}}

+
+ + +
+
+ + +
+
-- cgit v1.2.3-55-g7522