Просмотр исходного кода

Multiple Bug fixes UI restic (#4863)

* Repo with rclone got overwritten

* List repo snapshots instead

* Allow restore full snapshot

* Allow bulk delete snapshot

* Use correct folder name

* Add possibility to delete snapshot

* 2 mandetory arguments

* Fix bulk restore

* Set some values to test the preformance

* Slow down backup process

* Mute outoutput

* Export it

* Update example
Jaap Marcus 1 год назад
Родитель
Сommit
95e2fe5ed3

+ 3 - 3
bin/v-add-backup-host-restic

@@ -75,10 +75,10 @@ fi
 # Check if $repo starts with rclone
 if [[ $repo == "rclone:"* ]]; then
 	# remove rclone: from $repo
-	repo=$(echo "$repo" | sed 's/rclone://')
+	repo2=$(echo "$repo" | sed 's/rclone://')
 	# check if rclone is working
-	if ! rclone lsd "$repo" > /dev/null 2>&1; then
-		check_result $E_NOTEXIST "Rclone repository '$repo' does not exist"
+	if ! rclone lsd "$repo2" > /dev/null 2>&1; then
+		check_result $E_NOTEXIST "Rclone repository '$repo2' does not exist"
 	fi
 fi
 

+ 8 - 5
bin/v-backup-user-restic

@@ -2,9 +2,10 @@
 # info: backup system user with all its objects to restic backup
 # options: USER NOTIFY
 #
-# example: v-backup-user admin yes
+# example: v-backup-user-restic admin yes
+#
+# Backup user with all its objects to restic backup. If the repo doesn't exists a new one will be created.
 #
-# This function is used for backing up user with all its domains and databases.
 
 #----------------------------------------------------------#
 #                Variables & Functions                     #
@@ -60,18 +61,20 @@ if [ ! -f "$USER_DATA/restic.conf" ]; then
 	fi
 else
 	# Check if repo exists and is accessible with restic key
-	restic --repo "$REPO$user" --password-file $USER_DATA/restic.conf --json dump $snapshot /home/$user/backup/backup.conf > /home/$user/tmp/backup.conf
+	restic --repo "$REPO$user" --password-file $USER_DATA/restic.conf --json snapshots > /dev/null
 	if [ $? -ne 0 ]; then
 		# Send an email
 		echo "Unable to open restic backup. It might not exists or key is incorrect" | $SENDMAIL -s "$subj" "$email" "yes"
 		check_result $E_CONNECT "Unable to access restic repo"
 	fi
-	rm /home/$user/tmp/backup.conf
 fi
 
 # create backup of the user.conf an database
 $BIN/v-backup-user-config $user
-restic --repo "$REPO$user" --password-file $USER_DATA/restic.conf backup /home/$user
+export GOMAXPROCS=2
+export RESTIC_READ_CONCURRENCY=2
+ionice -c2 -n7 nice -n 19 restic --repo "$REPO$user" --limit-upload 10240 --read-concurrency 2 --password-file $USER_DATA/restic.conf backup /home/$user
+
 if [ $? -ne 0 ]; then
 	echo "Unable to create the backup" | $SENDMAIL -s "$subj" "$email" "yes"
 	check_result $E_BACKUP "Unable to backup user"

+ 71 - 0
bin/v-delete-user-backup-restic

@@ -0,0 +1,71 @@
+#!/bin/bash
+# info: delete a specific user snapshot from restic backup repository.
+# options: USER SNAPSHOT
+#
+# example: v-delete-user-backup-restic admin snapshot
+#
+# Delete a specific user snapshot from restic backup repository. It doesn't take in account any pruning done by the retention policy.
+# This function is used for deleting a specific user snapshot from restic backup repository.
+
+#----------------------------------------------------------#
+#                Variables & Functions                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+snapshot=$2
+
+# Includes
+# shellcheck source=/etc/hestiacp/hestia.conf
+source /etc/hestiacp/hestia.conf
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
+source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
+source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
+# shellcheck source=/usr/local/hestia/func/syshealth.sh
+source $HESTIA/func/syshealth.sh
+# load config file
+source_conf "$HESTIA/conf/hestia.conf"
+
+source_conf $HESTIA/conf/restic.conf
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+args_usage='USER SNAPSHOT'
+check_args '2' "$#" "$args_usage"
+is_format_valid 'user'
+is_object_valid 'user' 'USER' "$user"
+
+source_conf $HESTIA/conf/restic.conf
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+tmpdir=$(mktemp -p /home/$user/tmp/ -d)
+if [ ! -f "$tmpdir/backup.conf" ]; then
+	restic --repo "$REPO$user" --password-file "$USER_DATA/restic.conf" dump "$snapshot" "/home/$user/backup/backup.conf" > "$tmpdir/backup.conf"
+	if [ "$?" -ne 0 ]; then
+		check_result "$E_NOTEXIST" "Unable to download from snapshot"
+	fi
+fi
+
+restic --repo "$REPO$user" --password-file "$USER_DATA/restic.conf" forget "$snapshot"
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+sed -i "/v-delete-user-backup-restic '$user' '$snapshot' /d" $HESTIA/data/queue/backup.pipe
+
+# Logging
+$BIN/v-log-action "system" "Info" "Backup" "Restic snapshot successfully deleted (User: $user, Snapshot: $snapshot)."
+$BIN/v-log-action "$user" "Info" "Backup" "Restic snapshot successfully deleted (Snapshot: $snapshot)."
+log_event "$OK" "$ARGUMENTS"
+exit

+ 42 - 0
web/bulk/backup/incremental/index.php

@@ -0,0 +1,42 @@
+<?php
+use function Hestiacp\quoteshellarg\quoteshellarg;
+
+ob_start();
+include $_SERVER["DOCUMENT_ROOT"] . "/inc/main.php";
+
+if (empty($_POST["backup"])) {
+	header("Location: /list/backup/incremental/");
+	exit();
+}
+if (empty($_POST["action"])) {
+	header("Location: /list/backup/incremental/");
+	exit();
+}
+
+$backup = $_POST["backup"];
+$action = $_POST["action"];
+
+// Check token
+verify_csrf($_POST);
+
+switch ($action) {
+	case "delete":
+		$cmd = "v-delete-user-backup-restic";
+		break;
+	default:
+		header("Location: /list/backup/");
+		exit();
+}
+
+foreach ($backup as $value) {
+	$value = quoteshellarg($value);
+	exec(HESTIA_CMD . $cmd . " " . $user . " " . $value, $output, $return_var);
+	if ($return_var != 0) {
+		$_SESSION["error_msg"] = implode("<br>", $output);
+		if (empty($_SESSION["error_msg"])) {
+			$_SESSION["error_msg"] = _("Error: Hestia did not return any output.");
+		}
+	}
+}
+
+header("Location: /list/backup/incremental/");

+ 15 - 0
web/schedule/restore/incremental/index.php

@@ -19,6 +19,21 @@ if (empty($_GET["type"])) {
 		$output,
 		$return_var,
 	);
+	if ($return_var == 0) {
+		$_SESSION["error_msg"] = _(
+			"Task has been added to the queue. You will receive an email notification when your restore has been completed.",
+		);
+	} else {
+		$_SESSION["error_msg"] = implode("<br>", $output);
+		if (empty($_SESSION["error_msg"])) {
+			$_SESSION["error_msg"] = _("Error: Hestia did not return any output.");
+		}
+		if ($return_var == 4) {
+			$_SESSION["error_msg"] = _(
+				"An existing restoration task is already running. Please wait for it to finish before launching it again.",
+			);
+		}
+	}
 } else {
 	exec(
 		HESTIA_CMD .

+ 3 - 2
web/templates/pages/list_backup_detail_incremental.php

@@ -4,13 +4,14 @@
 		<div class="toolbar-buttons">
 			<a class="button button-secondary button-back js-button-back" href="/list/backup/incremental/"><i class="fas fa-arrow-left icon-blue"></i><?= _("Back") ?></a>
 			<?php if ($read_only !== "true") { ?>
-			<a href="/schedule/restore/incremental/?token=<?= $_SESSION["token"] ?>&backup=<?= htmlentities($_GET["backup"]) ?>" class="button button-secondary"><i class="fas fa-arrow-rotate-left icon-green"></i><?= _("Restore All") ?></a>
+			<a href="/schedule/restore/incremental/?token=<?= $_SESSION["token"] ?>&snapshot=<?= htmlentities($_GET["snapshot"]) ?>" class="button button-secondary"><i class="fas fa-arrow-rotate-left icon-green"></i><?= _("Restore All") ?></a>
 			<?php } ?>
 		</div>
 		<div class="toolbar-right">
 			<?php if ($read_only !== "true") { ?>
-				<form x-data x-bind="BulkEdit" action="/bulk/backup/incremental" method="post">
+				<form x-data x-bind="BulkEdit" action="/bulk/restore/incremental/" method="post">
 					<input type="hidden" name="token" value="<?= $_SESSION["token"] ?>">
+					<input type="hidden" name="snapshot" value="<?= htmlentities($_GET["snapshot"]) ?>">
 					<select class="form-select" name="action">
 						<option value=""><?= _("Apply to selected") ?></option>
 						<option value="restore"><?= _("Restore Snapshot") ?></option>

+ 3 - 3
web/templates/pages/list_backup_incremental.php

@@ -10,11 +10,11 @@
 		</div>
 		<div class="toolbar-right">
 			<?php if ($read_only !== "true") { ?>
-				<form x-data x-bind="BulkEdit" action="/bulk/backup/incremental" method="post">
+				<form x-data x-bind="BulkEdit" action="/bulk/backup/incremental/" method="post">
 					<input type="hidden" name="token" value="<?= $_SESSION["token"] ?>">
 					<select class="form-select" name="action">
 						<option value=""><?= _("Apply to selected") ?></option>
-						<option value="delete"><?= _("Delete Snapshot") ?></option>
+						<option value="delete"><?= _("Delete") ?></option>
 					</select>
 					<button type="submit" class="toolbar-input-submit" title="<?= _("Apply to selected") ?>">
 						<i class="fas fa-arrow-right"></i>
@@ -59,7 +59,7 @@
 		<div class="units-table-row js-unit">
 			<div class="units-table-cell">
 				<div>
-					<input id="check<?= $i ?>" class="js-unit-checkbox" type="checkbox" title="<?= _("Select") ?>" name="backup[]" value="<?= $key ?>" <?= $display_mode ?>>					<span class="u-hide-desktop"><label for="check<?= $i ?>" class="u-hide-desktop"><?= _("Select") ?></label></span>
+					<input id="check<?= $i ?>" class="js-unit-checkbox" type="checkbox" title="<?= _("Select") ?>" name="backup[]" value="<?= $value['short_id'] ?>" <?= $display_mode ?>>					<span class="u-hide-desktop"><label for="check<?= $i ?>" class="u-hide-desktop"><?= _("Select") ?></label></span>
 				</div>
 			</div>
 			<div class="units-table-cell units-table-heading-cell u-text-bold">