From f7d33b3d3b491719de366a4199ffd2ce53499ad0 Mon Sep 17 00:00:00 2001 From: "Buster \"Silver Eagle\" Neece" Date: Fri, 24 Jun 2022 10:36:55 -0500 Subject: [PATCH] Allow direct restore from the internal Docker backups volume. --- docker.sh | 76 +++++++++++-------- src/Console/Command/Backup/RestoreCommand.php | 36 ++++++++- 2 files changed, 75 insertions(+), 37 deletions(-) diff --git a/docker.sh b/docker.sh index c41bb3db5..dfa1c2b81 100755 --- a/docker.sh +++ b/docker.sh @@ -664,51 +664,61 @@ backup() { # ./docker.sh restore [/custom/backup/dir/custombackupname.zip] # restore() { - local BACKUP_PATH BACKUP_DIR BACKUP_FILENAME BACKUP_EXT - BACKUP_PATH=$(readlink -f ${1:-"./backup.tar.gz"}) - BACKUP_DIR=$(dirname -- "$BACKUP_PATH") - BACKUP_FILENAME=$(basename -- "$BACKUP_PATH") - BACKUP_EXT="${BACKUP_FILENAME##*.}" - shift - if [[ ! -f .env ]] || [[ ! -f azuracast.env ]]; then echo "AzuraCast hasn't been installed yet on this server." echo "You should run './docker.sh install' first before restoring." exit 1 fi - if [[ ! -f ${BACKUP_PATH} ]]; then - echo "File '${BACKUP_PATH}' does not exist. Nothing to restore." - exit 1 - fi - if ask "Restoring will remove any existing AzuraCast installation data, replacing it with your backup. Continue?" Y; then - docker-compose down -v + if [[ $1 != "" ]]; then + local BACKUP_PATH BACKUP_DIR BACKUP_FILENAME BACKUP_EXT + BACKUP_PATH=$(readlink -f ${1:-"./backup.tar.gz"}) + BACKUP_DIR=$(dirname -- "$BACKUP_PATH") + BACKUP_FILENAME=$(basename -- "$BACKUP_PATH") + BACKUP_EXT="${BACKUP_FILENAME##*.}" + shift - docker volume create azuracast_backups + if [[ ! -f ${BACKUP_PATH} ]]; then + echo "File '${BACKUP_PATH}' does not exist. Nothing to restore." + exit 1 + fi - # Move from local filesystem to Docker volume - docker run --rm -v "$BACKUP_DIR:/backup_src" \ - -v "azuracast_backups:/backup_dest" \ - busybox mv "/backup_src/${BACKUP_FILENAME}" "/backup_dest/${BACKUP_FILENAME}" + docker-compose down -v + docker volume create azuracast_backups - # Prepare permissions - if [[ $EUID -ne 0 ]]; then - .env --file .env set AZURACAST_PUID="$(id -u)" - .env --file .env set AZURACAST_PGID="$(id -g)" + # Move from local filesystem to Docker volume + docker run --rm -v "$BACKUP_DIR:/backup_src" \ + -v "azuracast_backups:/backup_dest" \ + busybox mv "/backup_src/${BACKUP_FILENAME}" "/backup_dest/${BACKUP_FILENAME}" + + # Prepare permissions + if [[ $EUID -ne 0 ]]; then + .env --file .env set AZURACAST_PUID="$(id -u)" + .env --file .env set AZURACAST_PGID="$(id -g)" + fi + + docker-compose run --rm web -- azuracast_restore "/var/azuracast/backups/${BACKUP_FILENAME}" "$@" + + # Move file back from volume to local filesystem + docker run --rm -v "azuracast_backups:/backup_src" \ + -v "$BACKUP_DIR:/backup_dest" \ + busybox mv "/backup_src/${BACKUP_FILENAME}" "/backup_dest/${BACKUP_FILENAME}" + + docker-compose down + docker-compose up -d + else + docker-compose down + + # Remove all volumes except the backup volume. + docker volume rm -f $(docker volume ls | grep -v "azuracast_backups" | awk 'NR>1 {print $2}') + + docker-compose run --rm web -- azuracast_restore "$@" + + docker-compose down + docker-compose up -d fi - - docker-compose run --rm web -- azuracast_restore "/var/azuracast/backups/${BACKUP_FILENAME}" "$@" - - # Move file back from volume to local filesystem - docker run --rm -v "azuracast_backups:/backup_src" \ - -v "$BACKUP_DIR:/backup_dest" \ - busybox mv "/backup_src/${BACKUP_FILENAME}" "/backup_dest/${BACKUP_FILENAME}" - - docker-compose down - docker-compose up -d fi - exit } diff --git a/src/Console/Command/Backup/RestoreCommand.php b/src/Console/Command/Backup/RestoreCommand.php index cf707f5a3..071af5dab 100644 --- a/src/Console/Command/Backup/RestoreCommand.php +++ b/src/Console/Command/Backup/RestoreCommand.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Console\Command\Backup; +use App\Entity\StorageLocation; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -22,7 +23,7 @@ class RestoreCommand extends AbstractBackupCommand { protected function configure(): void { - $this->addArgument('path', InputArgument::REQUIRED) + $this->addArgument('path', InputArgument::OPTIONAL) ->addOption('restore', null, InputOption::VALUE_NONE) ->addOption('release', null, InputOption::VALUE_NONE); } @@ -32,14 +33,39 @@ class RestoreCommand extends AbstractBackupCommand $io = new SymfonyStyle($input, $output); $path = $input->getArgument('path'); - $start_time = microtime(true); $io->title('AzuraCast Restore'); - $io->writeln('Please wait while the backup is restored...'); + + if (empty($path)) { + $filesRaw = glob(StorageLocation::DEFAULT_BACKUPS_PATH . '/*', GLOB_NOSORT) ?: []; + usort( + $filesRaw, + static fn($a, $b) => filemtime($b) <=> filemtime($a) + ); + + if (0 === count($filesRaw)) { + $io->getErrorStyle() + ->error('Backups directory has no available files. You must explicitly specify a backup file.'); + return 1; + } + + $files = []; + $i = 1; + foreach ($filesRaw as $filePath) { + $files[$i] = basename($filePath); + + if (10 === $i) { + break; + } + $i++; + } + + $path = $io->choice('Select backup file to restore:', $files, 1); + } if ('/' !== $path[0]) { - $path = '/var/azuracast/backups/' . $path; + $path = StorageLocation::DEFAULT_BACKUPS_PATH . '/' . $path; } if (!file_exists($path)) { @@ -52,6 +78,8 @@ class RestoreCommand extends AbstractBackupCommand return 1; } + $io->writeln('Please wait while the backup is restored...'); + // Extract tar.gz archive $io->section('Extracting backup file...');