Skip to content

Commit

Permalink
allow to restore the whole instance from backup
Browse files Browse the repository at this point in the history
Signed-off-by: szaimen <szaimen@e.mail.de>
  • Loading branch information
szaimen committed Mar 22, 2022
1 parent 31bba7a commit eff32d2
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 29 deletions.
49 changes: 47 additions & 2 deletions Containers/borgbackup/backupscript.sh
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ if [ "$BORG_MODE" = restore ]; then
echo "Could not mount the backup!"
exit 1
fi

# Save current aio password
AIO_PASSWORD="$(grep -oP '"password":"[a-zA-Z0-9 ]+"' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
AIO_PASSWORD="${AIO_PASSWORD##\"password\":\"}"
AIO_PASSWORD="${AIO_PASSWORD%\"}"

# Save current path
BORG_LOCATION="$(grep -oP '"borg_backup_host_location":"[\\/a-zA-Z0-9 ]+"' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)"
BORG_LOCATION="${BORG_LOCATION##\"borg_backup_host_location\":\"}"
BORG_LOCATION="${BORG_LOCATION%\"}"

if ! rsync --stats --archive --human-readable -vv --delete \
--exclude "nextcloud_aio_mastercontainer/session/"** \
--exclude "nextcloud_aio_mastercontainer/certs/"** \
Expand All @@ -183,8 +194,6 @@ if [ "$BORG_MODE" = restore ]; then
fi
umount /tmp/borg

# TODO: reset fetchtimes in configuration.json so that it doesn't get the latest directly...

# Inform user
get_expiration_time
echo "Restore finished successfully on $END_DATE_READABLE ($DURATION_READABLE)"
Expand All @@ -196,6 +205,22 @@ if [ "$BORG_MODE" = restore ]; then
# Set backup-mode to restore since it was a restore
sed -i 's/"backup-mode":"[a-z]\+"/"backup-mode":"restore"/g' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json

# Reset the AIO password to the currently used one
sed -i "s/\"password\":\"[a-zA-Z0-9 ]\+\"/\"password\":\"$AIO_PASSWORD\"/g" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json

# Reset the backup path to the currently used one
if [ -n "$BORG_LOCATION" ]; then
# shellcheck disable=SC2143
if [ -n "$(grep -oP '"borg_backup_host_location":"[\\/a-zA-Z0-9 ]+"' /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json)" ]; then
sed -i "s/\"borg_backup_host_location\":\"[\\/a-zA-Z0-9 ]\+\"/\"borg_backup_host_location\":\"$BORG_LOCATION\"/g" /nextcloud_aio_volumes/nextcloud_aio_mastercontainer/data/configuration.json
else
echo "Could not set the borg_backup_host_location as it was empty."
echo "Probably the regex did not match."
fi
else
echo "Could not get the borg_backup_host_location as it was empty."
echo "Probably the regex did not match."
fi
exit 0
fi

Expand All @@ -215,3 +240,23 @@ if [ "$BORG_MODE" = check ]; then
echo "Check finished successfully on $END_DATE_READABLE ($DURATION_READABLE)"
exit 0
fi

# Do the backup test
if [ "$BORG_MODE" = test ]; then
if ! [ -d "$BORG_BACKUP_DIRECTORY" ]; then
echo "No 'borg' directory in the given backup directory found!"
echo "Please adjust the directory so that the borg archive is positioned in a folder named 'borg' inside the given directory!"
exit 1
elif ! [ -f "$BORG_BACKUP_DIRECTORY/config" ]; then
echo "A 'borg' directory was found but could not find the borg archive."
echo "It must be positioned directly in the 'borg' subfolder."
exit 1
elif ! borg list "$BORG_BACKUP_DIRECTORY"; then
echo "The entered path seems to be valid but could not open the backup archive."
echo "Most likely the entered password was wrong so please adjust it accordingly!"
exit 1
else
echo "Everything looks fine so feel free to continue!"
exit 0
fi
fi
16 changes: 10 additions & 6 deletions Containers/borgbackup/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@
export BORG_BACKUP_DIRECTORY="/mnt/borgbackup/borg"

# Validate BORG_PASSWORD
if [ -z "$BORG_PASSWORD" ]; then
echo "BORG_PASSWORD is not allowed to be empty."
if [ -z "$BORG_PASSWORD" ] && [ -z "$BACKUP_RESTORE_PASSWORD" ]; then
echo "Neither BORG_PASSWORD nor BACKUP_RESTORE_PASSWORD are set."
exit 1
fi

# Export defaults
export BORG_PASSPHRASE="$BORG_PASSWORD"
# Export defaults
if [ -n "$BACKUP_RESTORE_PASSWORD" ]; then
export BORG_PASSPHRASE="$BACKUP_RESTORE_PASSWORD"
else
export BORG_PASSPHRASE="$BORG_PASSWORD"
fi
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes
export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes

# Validate BORG_MODE
if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != restore ] && [ "$BORG_MODE" != check ]; then
echo "No correct BORG_MODE mode applied. Valid are 'backup' and 'restore'."
if [ "$BORG_MODE" != backup ] && [ "$BORG_MODE" != restore ] && [ "$BORG_MODE" != check ] && [ "$BORG_MODE" != test ]; then
echo "No correct BORG_MODE mode applied. Valid are 'backup', 'check', 'restore' and 'test'."
exit 1
fi

Expand Down
3 changes: 2 additions & 1 deletion php/containers.json
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@
"environmentVariables": [
"BORG_PASSWORD=%BORGBACKUP_PASSWORD%",
"BORG_MODE=%BORGBACKUP_MODE%",
"SELECTED_RESTORE_TIME=%SELECTED_RESTORE_TIME%"
"SELECTED_RESTORE_TIME=%SELECTED_RESTORE_TIME%",
"BACKUP_RESTORE_PASSWORD=%BACKUP_RESTORE_PASSWORD%"
],
"volumes": [
{
Expand Down
15 changes: 2 additions & 13 deletions php/psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,10 @@
<MissingParamType occurrences="1">
<code>$args</code>
</MissingParamType>
<PossiblyInvalidArrayAccess occurrences="2">
<code>$request-&gt;getParsedBody()['borg_backup_host_location']</code>
<code>$request-&gt;getParsedBody()['domain']</code>
</PossiblyInvalidArrayAccess>
<PossiblyNullArgument occurrences="2">
<code>$request-&gt;getParsedBody()['borg_backup_host_location']</code>
<code>$request-&gt;getParsedBody()['domain']</code>
</PossiblyNullArgument>
<PossiblyNullArrayAccess occurrences="2">
<code>$request-&gt;getParsedBody()['borg_backup_host_location']</code>
<code>$request-&gt;getParsedBody()['domain']</code>
</PossiblyNullArrayAccess>
</file>
<file src="src/Controller/DockerController.php">
<MissingParamType occurrences="7">
<MissingParamType occurrences="8">
<code>$args</code>
<code>$args</code>
<code>$args</code>
<code>$args</code>
Expand Down
2 changes: 2 additions & 0 deletions php/public/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
$app->post('/api/docker/start', AIO\Controller\DockerController::class . ':StartContainer');
$app->post('/api/docker/backup', AIO\Controller\DockerController::class . ':StartBackupContainerBackup');
$app->post('/api/docker/backup-check', AIO\Controller\DockerController::class . ':StartBackupContainerCheck');
$app->post('/api/docker/backup-test', AIO\Controller\DockerController::class . ':StartBackupContainerTest');
$app->post('/api/docker/restore', AIO\Controller\DockerController::class . ':StartBackupContainerRestore');
$app->post('/api/docker/stop', AIO\Controller\DockerController::class . ':StopContainer');
$app->get('/api/docker/logs', AIO\Controller\DockerController::class . ':GetLogs');
Expand Down Expand Up @@ -90,6 +91,7 @@
'is_onlyoffice_enabled' => $configurationManager->isOnlyofficeEnabled(),
'is_collabora_enabled' => $configurationManager->isCollaboraEnabled(),
'is_talk_enabled' => $configurationManager->isTalkEnabled(),
'borg_restore_password' => $configurationManager->GetBorgRestorePassword(),
]);
})->setName('profile');
$app->get('/login', function ($request, $response, $args) use ($container) {
Expand Down
12 changes: 10 additions & 2 deletions php/src/Controller/ConfigurationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public function __construct(
public function SetConfig(Request $request, Response $response, $args) : Response {
try {
if (isset($request->getParsedBody()['domain'])) {
$this->configurationManager->SetDomain($request->getParsedBody()['domain']);
$domain = $request->getParsedBody()['domain'] ?? '';
$this->configurationManager->SetDomain($domain);
}

if (isset($request->getParsedBody()['current-master-password']) || isset($request->getParsedBody()['new-master-password'])) {
Expand All @@ -32,7 +33,14 @@ public function SetConfig(Request $request, Response $response, $args) : Respons
}

if (isset($request->getParsedBody()['borg_backup_host_location'])) {
$this->configurationManager->SetBorgBackupHostLocation($request->getParsedBody()['borg_backup_host_location']);
$location = $request->getParsedBody()['borg_backup_host_location'] ?? '';
$this->configurationManager->SetBorgBackupHostLocation($location);
}

if (isset($request->getParsedBody()['borg_restore_host_location']) || isset($request->getParsedBody()['borg_restore_password'])) {
$restoreLocation = $request->getParsedBody()['borg_restore_host_location'] ?? '';
$borgPassword = $request->getParsedBody()['borg_restore_password'] ?? '';
$this->configurationManager->SetBorgRestoreHostLocationAndPassword($restoreLocation, $borgPassword);
}

if (isset($request->getParsedBody()['options-form'])) {
Expand Down
14 changes: 14 additions & 0 deletions php/src/Controller/DockerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,20 @@ public function StartBackupContainerRestore(Request $request, Response $response
return $response->withStatus(201)->withHeader('Location', '/');
}

public function StartBackupContainerTest(Request $request, Response $response, $args) : Response {
$config = $this->configurationManager->GetConfig();
$config['backup-mode'] = 'test';
$this->configurationManager->WriteConfig($config);

$id = self::TOP_CONTAINER;
$this->PerformRecursiveContainerStop($id);

$id = 'nextcloud-aio-borgbackup';
$this->PerformRecursiveContainerStart($id);

return $response->withStatus(201)->withHeader('Location', '/');
}

public function StartContainer(Request $request, Response $response, $args) : Response
{
$uri = $request->getUri();
Expand Down
38 changes: 38 additions & 0 deletions php/src/Data/ConfigurationManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ public function SetDomain(string $domain) : void {
// Write domain
$config = $this->GetConfig();
$config['domain'] = $domain;
// Reset the borg restore password when setting the domain
$config['borg_restore_password'] = '';
$this->WriteConfig($config);
}

Expand Down Expand Up @@ -308,6 +310,33 @@ public function SetBorgBackupHostLocation(string $location) : void {
$this->WriteConfig($config);
}

/**
* @throws InvalidSettingConfigurationException
*/
public function SetBorgRestoreHostLocationAndPassword(string $location, string $password) : void {
if ($location === '') {
throw new InvalidSettingConfigurationException("Please enter a path!");
}

$isValidPath = false;
if (str_starts_with($location, '/') && !str_ends_with($location, '/')) {
$isValidPath = true;
}

if(!$isValidPath) {
throw new InvalidSettingConfigurationException("The path may start with '/mnt/', '/media/' or '/host_mnt/' or may be equal to '/var/backups'.");
}

if ($password === '') {
throw new InvalidSettingConfigurationException("Please enter the password!");
}

$config = $this->GetConfig();
$config['borg_backup_host_location'] = $location;
$config['borg_restore_password'] = $password;
$this->WriteConfig($config);
}

/**
* @throws InvalidSettingConfigurationException
*/
Expand Down Expand Up @@ -384,6 +413,15 @@ public function GetBorgBackupHostLocation() : string {
return $config['borg_backup_host_location'];
}

public function GetBorgRestorePassword() : string {
$config = $this->GetConfig();
if(!isset($config['borg_restore_password'])) {
$config['borg_restore_password'] = '';
}

return $config['borg_restore_password'];
}

public function GetBorgBackupMode() : string {
$config = $this->GetConfig();
if(!isset($config['backup-mode'])) {
Expand Down
2 changes: 2 additions & 0 deletions php/src/Docker/DockerActionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ public function CreateContainer(Container $container) : void {
$replacements[1] = $this->configurationManager->GetApachePort();
} elseif ($out[1] === 'NEXTCLOUD_MOUNT') {
$replacements[1] = $this->configurationManager->GetNextcloudMount();
} elseif ($out[1] === 'BACKUP_RESTORE_PASSWORD') {
$replacements[1] = $this->configurationManager->GetBorgRestorePassword();
} elseif ($out[1] === 'CLAMAV_ENABLED') {
if ($this->configurationManager->isClamavEnabled()) {
$replacements[1] = 'yes';
Expand Down
Loading

0 comments on commit eff32d2

Please sign in to comment.