autorestic/src/backup.ts

112 lines
3.1 KiB
TypeScript
Raw Normal View History

2019-06-20 23:09:47 +02:00
import { Writer } from 'clitastic'
2019-12-24 16:52:27 +01:00
import { mkdirSync } from 'fs'
2019-06-20 23:09:47 +02:00
import { config, VERBOSE } from './autorestic'
import { getEnvFromBackend } from './backend'
2019-12-24 16:52:27 +01:00
import { LocationFromPrefixes } from './config'
import { Locations, Location, Backend } from './types'
import {
exec,
pathRelativeToConfigFile,
getFlagsFromLocation,
makeArrayIfIsNot,
execPlain,
2019-12-24 16:52:27 +01:00
MeasureDuration,
fill,
decodeLocationFromPrefix,
checkIfDockerVolumeExistsOrFail,
getPathFromVolume,
} from './utils'
2019-06-20 23:09:47 +02:00
2019-12-03 23:37:55 +01:00
2019-12-24 16:52:27 +01:00
export const backupFromFilesystem = (from: string, location: Location, backend: Backend, tags?: string[]) => {
const path = pathRelativeToConfigFile(from)
const { out, err, status } = exec(
2019-12-24 16:52:27 +01:00
'restic',
['backup', '.', ...getFlagsFromLocation(location, 'backup')],
{ env: getEnvFromBackend(backend), cwd: path },
)
if (VERBOSE) console.log(out, err)
if (status != 0 || err.length > 0)
throw new Error(err)
2019-12-24 16:52:27 +01:00
}
export const backupFromVolume = (volume: string, location: Location, backend: Backend) => {
const tmp = getPathFromVolume(volume)
2019-12-24 16:52:27 +01:00
try {
mkdirSync(tmp)
checkIfDockerVolumeExistsOrFail(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 /data /backup`)
execPlain(`docker run --rm -v ${volume}:/data -v ${tmp}:/backup alpine tar cf /backup/archive.tar -C /data .`)
backupFromFilesystem(tmp, location, backend)
} catch (e) {
throw e
2019-12-24 16:52:27 +01:00
} finally {
execPlain(`rm -rf ${tmp}`)
}
}
2019-12-04 20:38:04 +01:00
export const backupSingle = (name: string, to: string, location: Location) => {
const delta = new MeasureDuration()
2019-12-03 23:37:55 +01:00
const writer = new Writer(name + to.blue + ' : ' + 'Backing up... ⏳')
2019-10-26 21:50:48 +02:00
2019-12-24 16:52:27 +01:00
try {
const backend = config.backends[to]
const [type, value] = decodeLocationFromPrefix(location.from)
2019-06-20 23:09:47 +02:00
2019-12-24 16:52:27 +01:00
switch (type) {
2019-06-20 23:09:47 +02:00
2019-12-24 16:52:27 +01:00
case LocationFromPrefixes.Filesystem:
backupFromFilesystem(value, location, backend)
break
case LocationFromPrefixes.DockerVolume:
backupFromVolume(value, location, backend)
break
}
writer.done(`${name}${to.blue} : ${'Done ✓'.green} (${delta.finished(true)})`)
} catch (e) {
writer.done(`${name}${to.blue} : ${'Failed!'.red} (${delta.finished(true)}) ${e.message}`)
}
}
2019-06-20 23:09:47 +02:00
2019-12-04 20:38:04 +01:00
export const backupLocation = (name: string, location: Location) => {
2019-12-03 23:37:55 +01:00
const display = name.yellow + ' ▶ '
const filler = fill(name.length + 3)
2019-12-04 23:35:41 +01:00
let first = true
2019-12-05 00:24:20 +01:00
if (location.hooks && location.hooks.before)
for (const command of makeArrayIfIsNot(location.hooks.before)) {
2019-12-24 16:52:27 +01:00
const cmd = execPlain(command, {})
console.log(cmd.out, cmd.err)
2019-12-05 00:24:20 +01:00
}
for (const t of makeArrayIfIsNot(location.to)) {
2019-12-04 23:35:41 +01:00
backupSingle(first ? display : filler, t, location)
if (first) first = false
}
2019-12-05 00:24:20 +01:00
if (location.hooks && location.hooks.after)
for (const command of makeArrayIfIsNot(location.hooks.after)) {
const cmd = execPlain(command)
2019-12-24 16:52:27 +01:00
console.log(cmd.out, cmd.err)
2019-12-05 00:24:20 +01:00
}
2019-06-20 23:09:47 +02:00
}
2019-12-04 20:38:04 +01:00
export const backupAll = (locations?: Locations) => {
if (!locations)
2019-12-04 20:38:04 +01:00
locations = config.locations
2019-12-03 23:37:55 +01:00
console.log('\nBacking Up'.underline.grey)
2019-12-04 20:38:04 +01:00
for (const [name, location] of Object.entries(locations))
backupLocation(name, location)
}