parent
2fd9e2dd22
commit
e80db74af4
@ -1,10 +1,19 @@
|
|||||||
|
# Editors
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Node
|
||||||
node_modules/
|
node_modules/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
.idea
|
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
|
||||||
|
# Build & Runtime
|
||||||
bin
|
bin
|
||||||
lib
|
lib
|
||||||
data
|
data
|
||||||
|
restore
|
||||||
|
docker
|
||||||
|
Dockerfile
|
||||||
|
|
||||||
|
# Config
|
||||||
.autorestic.yml
|
.autorestic.yml
|
||||||
|
.docker.yml
|
@ -0,0 +1,82 @@
|
|||||||
|
import { Writer } from 'clitastic'
|
||||||
|
import { resolve } from 'path'
|
||||||
|
|
||||||
|
import { config } from './autorestic'
|
||||||
|
import { getEnvFromBackend } from './backend'
|
||||||
|
import { LocationFromPrefixes } from './config'
|
||||||
|
import { Backend } from './types'
|
||||||
|
import {
|
||||||
|
checkIfDockerVolumeExistsOrFail,
|
||||||
|
ConfigError,
|
||||||
|
decodeLocationFromPrefix,
|
||||||
|
exec, execPlain,
|
||||||
|
hash,
|
||||||
|
pathRelativeToConfigFile,
|
||||||
|
} from './utils'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const restoreToFilesystem = (from: string, to: string, backend: Backend) => {
|
||||||
|
exec(
|
||||||
|
'restic',
|
||||||
|
['restore', 'latest', '--path', resolve(from), '--target', to],
|
||||||
|
{ env: getEnvFromBackend(backend) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const restoreToVolume = (volume: string, backend: Backend) => {
|
||||||
|
const tmp = pathRelativeToConfigFile(hash(volume))
|
||||||
|
|
||||||
|
try {
|
||||||
|
restoreToFilesystem(tmp, tmp, backend)
|
||||||
|
try {
|
||||||
|
checkIfDockerVolumeExistsOrFail(volume)
|
||||||
|
} catch {
|
||||||
|
execPlain(`docker volume create ${volume}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For incremental backups. Unfortunately due to how the docker mounts work the permissions get lost.
|
||||||
|
// execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine cp -aT /backup /data`)
|
||||||
|
execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine tar xf /backup/archive.tar -C /data`)
|
||||||
|
} finally {
|
||||||
|
execPlain(`rm -rf ${tmp}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const restoreSingle = (locationName: string, from: string, to?: string) => {
|
||||||
|
if (!config) throw ConfigError
|
||||||
|
|
||||||
|
const location = config.locations[locationName]
|
||||||
|
|
||||||
|
const baseText = locationName.green + '\t\t'
|
||||||
|
const w = new Writer(baseText + `Starting...`)
|
||||||
|
|
||||||
|
let backendName: string = Array.isArray(location.to) ? location.to[0] : location.to
|
||||||
|
if (from) {
|
||||||
|
if (!location.to.includes(from)) {
|
||||||
|
w.done(baseText + `Backend ${from} is not a valid location for ${locationName}`.red)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
backendName = from
|
||||||
|
w.replaceLn(baseText + `Restoring from ${backendName.blue}...`)
|
||||||
|
} else if (Array.isArray(location.to) && location.to.length > 1) {
|
||||||
|
w.replaceLn(baseText + `Restoring from ${backendName.blue}...\tTo select a specific backend pass the ${'--from'.blue} flag`)
|
||||||
|
}
|
||||||
|
const backend = config.backends[backendName]
|
||||||
|
|
||||||
|
const [type, value] = decodeLocationFromPrefix(location.from)
|
||||||
|
switch (type) {
|
||||||
|
|
||||||
|
case LocationFromPrefixes.Filesystem:
|
||||||
|
if (!to) throw new Error(`You need to specify the restore path with --to`.red)
|
||||||
|
restoreToFilesystem(value, to, backend)
|
||||||
|
break
|
||||||
|
|
||||||
|
case LocationFromPrefixes.DockerVolume:
|
||||||
|
restoreToVolume(value, backend)
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
w.done(locationName.green + '\t\tDone 🎉')
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in new issue