2019-12-03 01:26:03 +01:00
|
|
|
"""
|
|
|
|
Restic commands
|
|
|
|
"""
|
2019-11-15 14:23:56 +01:00
|
|
|
import logging
|
2019-12-04 03:12:36 +01:00
|
|
|
from typing import List, Tuple
|
2019-11-12 12:39:49 +01:00
|
|
|
from subprocess import Popen, PIPE
|
2019-12-03 09:40:02 +01:00
|
|
|
from restic_compose_backup import commands
|
2019-04-13 19:04:54 +02:00
|
|
|
|
2019-11-15 14:23:56 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2019-04-13 19:04:54 +02:00
|
|
|
|
2019-12-03 04:23:47 +01:00
|
|
|
def init_repo(repository: str):
|
2019-11-15 14:23:56 +01:00
|
|
|
"""
|
|
|
|
Attempt to initialize the repository.
|
|
|
|
Doing this after the repository is initialized
|
|
|
|
"""
|
2019-12-03 05:06:28 +01:00
|
|
|
return commands.run(restic(repository, [
|
2019-04-13 19:04:54 +02:00
|
|
|
"init",
|
2019-12-03 05:06:28 +01:00
|
|
|
]))
|
2019-04-13 19:04:54 +02:00
|
|
|
|
|
|
|
|
2019-12-04 22:17:42 +01:00
|
|
|
def backup_files(repository: str, source='/volumes'):
|
2019-12-03 05:06:28 +01:00
|
|
|
return commands.run(restic(repository, [
|
2019-04-13 19:04:54 +02:00
|
|
|
"--verbose",
|
|
|
|
"backup",
|
2019-11-29 01:25:00 +01:00
|
|
|
source,
|
2019-12-03 05:06:28 +01:00
|
|
|
]))
|
2019-04-13 19:04:54 +02:00
|
|
|
|
|
|
|
|
2019-12-03 05:00:47 +01:00
|
|
|
def backup_from_stdin(repository: str, filename: str, source_command: List[str]):
|
2019-12-03 04:23:47 +01:00
|
|
|
"""
|
|
|
|
Backs up from stdin running the source_command passed in.
|
|
|
|
It will appear in restic with the filename (including path) passed in.
|
|
|
|
"""
|
2019-12-03 05:06:28 +01:00
|
|
|
dest_command = restic(repository, [
|
|
|
|
'backup',
|
|
|
|
'--stdin',
|
|
|
|
'--stdin-filename',
|
|
|
|
filename,
|
|
|
|
])
|
2019-11-29 01:25:00 +01:00
|
|
|
|
2019-12-03 04:23:47 +01:00
|
|
|
# pipe source command into dest command
|
2019-12-08 01:16:10 +01:00
|
|
|
source_process = Popen(source_command, stdout=PIPE, bufsize=65536)
|
|
|
|
dest_process = Popen(dest_command, stdin=source_process.stdout, stdout=PIPE, stderr=PIPE, bufsize=65536)
|
2019-12-04 01:57:52 +01:00
|
|
|
stdout, stderr = dest_process.communicate()
|
|
|
|
|
2019-12-06 17:19:51 +01:00
|
|
|
# Ensure both processes exited with code 0
|
|
|
|
source_exit, dest_exit = source_process.poll(), dest_process.poll()
|
|
|
|
exit_code = 0 if (source_exit == 0 and dest_exit == 0) else 1
|
|
|
|
|
2019-12-04 01:57:52 +01:00
|
|
|
if stdout:
|
2019-12-06 17:19:51 +01:00
|
|
|
commands.log_std('stdout', stdout, logging.DEBUG if exit_code == 0 else logging.ERROR)
|
2019-12-04 01:57:52 +01:00
|
|
|
|
|
|
|
if stderr:
|
2019-12-06 17:19:51 +01:00
|
|
|
commands.log_std('stderr', stderr, logging.ERROR)
|
2019-12-03 07:29:52 +01:00
|
|
|
|
2019-12-06 17:19:51 +01:00
|
|
|
return exit_code
|
2019-11-29 01:25:00 +01:00
|
|
|
|
|
|
|
|
2019-12-04 22:02:53 +01:00
|
|
|
def snapshots(repository: str, last=True) -> Tuple[str, str]:
|
2019-12-08 05:09:05 +01:00
|
|
|
"""Returns the stdout and stderr info"""
|
2019-12-04 22:02:53 +01:00
|
|
|
args = ["snapshots"]
|
|
|
|
if last:
|
2019-12-05 11:09:36 +01:00
|
|
|
args.append('--last')
|
2019-12-04 22:02:53 +01:00
|
|
|
return commands.run_capture_std(restic(repository, args))
|
2019-04-13 19:04:54 +02:00
|
|
|
|
|
|
|
|
2019-12-08 05:09:05 +01:00
|
|
|
def is_initialized(repository: str) -> bool:
|
|
|
|
"""
|
|
|
|
Checks if a repository is initialized using snapshots command.
|
|
|
|
Note that this cannot separate between uninitalized repo
|
|
|
|
and other errors, but this method is reccomended by the restic
|
|
|
|
community.
|
|
|
|
"""
|
|
|
|
return commands.run(restic(repository, ["snapshots", '--last'])) == 0
|
|
|
|
|
|
|
|
|
2020-11-16 11:31:19 +01:00
|
|
|
def forget(repository: str, keeplast: str, hourly: str, daily: str, weekly: str, monthly: str, yearly: str, tags: str):
|
2019-12-05 12:42:21 +01:00
|
|
|
return commands.run(restic(repository, [
|
2019-12-04 23:24:56 +01:00
|
|
|
'forget',
|
2019-12-09 03:57:16 +01:00
|
|
|
'--group-by',
|
2020-11-16 11:31:19 +01:00
|
|
|
'paths,tags',
|
|
|
|
'-keep-last',
|
|
|
|
keeplast,
|
|
|
|
'--keep-hourly',
|
2020-11-16 12:07:19 +01:00
|
|
|
hourly,
|
2019-12-04 23:24:56 +01:00
|
|
|
'--keep-daily',
|
|
|
|
daily,
|
|
|
|
'--keep-weekly',
|
|
|
|
weekly,
|
|
|
|
'--keep-monthly',
|
|
|
|
monthly,
|
|
|
|
'--keep-yearly',
|
|
|
|
yearly,
|
2020-11-16 11:31:19 +01:00
|
|
|
'--keep-tag',
|
2020-11-16 12:07:19 +01:00
|
|
|
tags,
|
2019-12-05 12:42:21 +01:00
|
|
|
]))
|
2019-12-04 23:24:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
def prune(repository: str):
|
2019-12-05 12:42:21 +01:00
|
|
|
return commands.run(restic(repository, [
|
2019-12-04 23:24:56 +01:00
|
|
|
'prune',
|
2019-12-05 12:42:21 +01:00
|
|
|
]))
|
2019-12-04 23:24:56 +01:00
|
|
|
|
|
|
|
|
2019-12-03 04:23:47 +01:00
|
|
|
def check(repository: str):
|
2019-12-03 05:06:28 +01:00
|
|
|
return commands.run(restic(repository, [
|
2019-04-13 19:04:54 +02:00
|
|
|
"check",
|
2019-12-08 04:50:33 +01:00
|
|
|
# "--with-cache",
|
2019-12-03 05:06:28 +01:00
|
|
|
]))
|
2019-12-03 05:00:47 +01:00
|
|
|
|
|
|
|
|
|
|
|
def restic(repository: str, args: List[str]):
|
|
|
|
"""Generate restic command"""
|
|
|
|
return [
|
|
|
|
"restic",
|
|
|
|
"-r",
|
|
|
|
repository,
|
|
|
|
] + args
|