From d685e511453560091bd0f48ec39345abd9b86bd4 Mon Sep 17 00:00:00 2001 From: "Guillaume \"B.B.\" Van Hemmen" Date: Wed, 21 Aug 2024 13:27:20 +0200 Subject: [PATCH] #0 - Add volume restoration functionality Implement functions to list and select archives for restoration based on existing volumes. Introduce a new process to restore volumes from backups, ensuring archives are checked and volumes are recreated correctly. --- src/commands/docker-volume-manager.ts | 63 ++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/src/commands/docker-volume-manager.ts b/src/commands/docker-volume-manager.ts index fbc9fdf..ec9093e 100644 --- a/src/commands/docker-volume-manager.ts +++ b/src/commands/docker-volume-manager.ts @@ -81,7 +81,7 @@ const listAndSelectDockerVolumes = async (toolbox: Toolbox): Promise = const {selectedVolumes} = await prompt.ask({ type: 'multiselect', name: 'selectedVolumes', - message: 'Select the volumes you want to backup:', + message: 'Select the volumes you want to treat:', choices: volumeList, }) as { selectedVolumes: string[] }; @@ -116,6 +116,62 @@ const runVolumeBackup = async (toolbox: Toolbox, workingDir: string, volumes: st } } +const listAndSelectArchives = async (toolbox: Toolbox, workingDir: string, volumes: string[]): Promise =>{ + const {print, filesystem} = toolbox + + print.divider(); + + print.warning('To avoid problem with docker compose, we list only the archive to restore if'); + print.warning('there is an EXISTING volume of the same name. Please, ensure that the volumes'); + print.warning('are created prior to run this tool.'); + + const spinner = print.spin('running docker volume ls'); + + // test if an archive for the name of the volume exist if yes add it to the list + try { + const archives: string[] = []; + for (const volume of volumes) { + // check if file exist + if (filesystem.exists(`${workingDir}/${volume}.tar`)) { + spinner.succeed(`Archive found for ${volume}.`); + archives.push(`${volume}`); + } else { + spinner.fail(`No archive found for ${volume}.`); + } + } + + return archives; + + } catch (listAndSelectArchivesError) { + spinner.fail('Failed to list docker volumes or to access backups!') + process.exit(4) + } +} + +const runVolumeRestore = async (toolbox: Toolbox, workingDir: string, archives: string[]) => { + const {print, system} = toolbox; + + print.divider(); + print.info('starting restore process'); + print.newline(); + + const spinner = print.spin(); + + for (const archive of archives) { + try { + spinner.start(`restore volume ${archive}...`) + + await system.run(`docker run -v "${archive}":/volume -v "${workingDir}":/tmp alpine sh -c "rm -rf /volume/* && tar -p -xf /tmp/${archive}.tar -C /volume"`); + + spinner.succeed(`volume ${archive} restored!`) + } catch (error) { + spinner.fail(`volume ${archive} restore failed!`) + print.error(error); + print.newline(); + } + } +} + const command: GluegunCommand = { name: 'docker-volume-manager', run: async (toolbox) => { @@ -133,7 +189,6 @@ const command: GluegunCommand = { if (choice === 'Backup volume') { // select the backup location folder - // @ts-ignore const workingFolder = await getAndValidateBackupFolder(toolbox); // list and select the volumes @@ -145,10 +200,14 @@ const command: GluegunCommand = { print.success('Your volume have been backed up!') } else if (choice === 'Restore volumes') { // select the backup location folder + const workingFolder = await getAndValidateBackupFolder(toolbox); // list and select the archives to restore + const volumes = await listAndSelectDockerVolumes(toolbox); + const archives = await listAndSelectArchives(toolbox, workingFolder, volumes); // run the restore + await runVolumeRestore(toolbox, workingFolder, archives); print.success('your backup have been restored!'); } else if (choice === 'exit') { -- 2.45.2