2019-04-15 16:31:08 +00:00
|
|
|
import argparse
|
2019-04-19 00:18:32 +00:00
|
|
|
import pprint
|
2019-11-15 13:23:56 +00:00
|
|
|
import logging
|
2019-04-15 16:31:08 +00:00
|
|
|
|
2019-04-15 15:25:42 +00:00
|
|
|
from restic_volume_backup.config import Config
|
|
|
|
from restic_volume_backup.containers import RunningContainers
|
2019-04-17 01:45:51 +00:00
|
|
|
from restic_volume_backup import backup_runner
|
|
|
|
from restic_volume_backup import restic
|
2019-04-13 17:04:54 +00:00
|
|
|
|
2019-11-15 13:23:56 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
def setup_logger(level=logging.INFO):
|
|
|
|
logger.setLevel(level)
|
|
|
|
ch = logging.StreamHandler()
|
|
|
|
ch.setLevel(logging.DEBUG)
|
|
|
|
ch.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
|
|
|
|
logger.addHandler(ch)
|
|
|
|
|
|
|
|
|
|
|
|
setup_logger()
|
|
|
|
|
2019-04-13 17:04:54 +00:00
|
|
|
|
|
|
|
def main():
|
2019-11-15 13:23:56 +00:00
|
|
|
"""CLI entrypoint"""
|
2019-04-15 16:31:08 +00:00
|
|
|
args = parse_args()
|
2019-04-16 00:18:49 +00:00
|
|
|
config = Config()
|
2019-04-13 17:04:54 +00:00
|
|
|
containers = RunningContainers()
|
|
|
|
|
2019-04-15 16:31:08 +00:00
|
|
|
if args.action == 'status':
|
2019-04-18 03:01:02 +00:00
|
|
|
status(config, containers)
|
2019-04-16 22:08:24 +00:00
|
|
|
|
2019-04-18 03:01:02 +00:00
|
|
|
elif args.action == 'backup':
|
|
|
|
backup(config, containers)
|
2019-04-16 22:08:24 +00:00
|
|
|
|
2019-04-18 03:01:02 +00:00
|
|
|
elif args.action == 'start-backup-process':
|
|
|
|
start_backup_process(config, containers)
|
2019-04-13 17:04:54 +00:00
|
|
|
|
2019-04-17 02:38:15 +00:00
|
|
|
|
2019-04-18 03:01:02 +00:00
|
|
|
def status(config, containers):
|
2019-11-12 11:39:49 +00:00
|
|
|
"""Outputs the backup config for the compose setup"""
|
2019-04-18 03:34:51 +00:00
|
|
|
|
2019-11-15 13:23:56 +00:00
|
|
|
logger.info("Backup config for compose project '%s'", containers.this_container.project_name)
|
|
|
|
logger.info("Current service: %s", containers.this_container.name)
|
|
|
|
logger.info("Backup process: %s", containers.backup_process_container.name
|
|
|
|
if containers.backup_process_container else 'Not Running')
|
|
|
|
logger.info("Backup running: %s", containers.backup_process_running)
|
2019-04-17 18:20:52 +00:00
|
|
|
|
2019-04-18 22:00:28 +00:00
|
|
|
backup_containers = containers.containers_for_backup()
|
|
|
|
for container in backup_containers:
|
|
|
|
if container.backup_enabled:
|
2019-11-15 13:23:56 +00:00
|
|
|
logger.info('service: %s', container.service_name)
|
2019-04-18 22:00:28 +00:00
|
|
|
for mount in container.filter_mounts():
|
2019-11-15 13:23:56 +00:00
|
|
|
logger.info(' - %s', mount.source)
|
2019-04-18 22:00:28 +00:00
|
|
|
|
|
|
|
if len(backup_containers) == 0:
|
2019-11-15 13:23:56 +00:00
|
|
|
logger.info("No containers in the project has 'restic-volume-backup.enabled' label")
|
2019-04-18 03:01:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
def backup(config, containers):
|
2019-11-15 13:23:56 +00:00
|
|
|
"""Request a backup to start"""
|
2019-04-18 03:01:02 +00:00
|
|
|
# Make sure we don't spawn multiple backup processes
|
|
|
|
if containers.backup_process_running:
|
2019-11-12 11:39:49 +00:00
|
|
|
raise ValueError("Backup process already running")
|
2019-04-18 03:01:02 +00:00
|
|
|
|
2019-11-15 13:23:56 +00:00
|
|
|
logger.info("Initializing repository")
|
2019-04-18 03:01:02 +00:00
|
|
|
|
|
|
|
# TODO: Errors when repo already exists
|
|
|
|
restic.init_repo(config.repository)
|
|
|
|
|
2019-11-15 13:23:56 +00:00
|
|
|
logger.info("Starting backup container..")
|
2019-04-19 00:18:32 +00:00
|
|
|
|
|
|
|
# Map all volumes from the backup container into the backup process container
|
2019-11-15 13:23:56 +00:00
|
|
|
volumes = containers.this_container.volumes
|
2019-04-19 00:18:32 +00:00
|
|
|
|
|
|
|
# Map volumes from other containers we are backing up
|
|
|
|
mounts = containers.generate_backup_mounts('/backup')
|
|
|
|
volumes.update(mounts)
|
|
|
|
pprint.pprint(volumes, indent=2)
|
|
|
|
|
2019-04-18 03:01:02 +00:00
|
|
|
backup_runner.run(
|
|
|
|
image=containers.this_container.image,
|
|
|
|
command='restic-volume-backup start-backup-process',
|
2019-04-19 00:18:32 +00:00
|
|
|
volumes=volumes,
|
2019-11-12 11:39:49 +00:00
|
|
|
environment=containers.this_container.environment,
|
2019-04-18 03:08:35 +00:00
|
|
|
labels={
|
|
|
|
"restic-volume-backup.backup_process": 'True',
|
|
|
|
"com.docker.compose.project": containers.this_container.project_name,
|
|
|
|
},
|
2019-04-18 03:01:02 +00:00
|
|
|
)
|
2019-04-13 23:35:14 +00:00
|
|
|
|
|
|
|
|
2019-04-18 03:08:35 +00:00
|
|
|
def start_backup_process(config, containers):
|
|
|
|
"""Start the backup process container"""
|
2019-11-12 11:39:49 +00:00
|
|
|
if (not containers.backup_process_container
|
|
|
|
or containers.this_container == containers.backup_process_container is False):
|
2019-04-18 03:44:59 +00:00
|
|
|
print(
|
|
|
|
"Cannot run backup process in this container. Use backup command instead. "
|
|
|
|
"This will spawn a new container with the necessary mounts."
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
2019-11-15 13:23:56 +00:00
|
|
|
logger.info("start-backup-process")
|
2019-04-18 03:08:35 +00:00
|
|
|
status(config, containers)
|
2019-11-15 13:23:56 +00:00
|
|
|
|
|
|
|
# Waste a few seconds faking a backup
|
|
|
|
print("Fake backup running")
|
2019-04-18 05:22:07 +00:00
|
|
|
import time
|
|
|
|
for i in range(5):
|
|
|
|
time.sleep(1)
|
|
|
|
print(i)
|
2019-04-18 03:08:35 +00:00
|
|
|
|
2019-11-15 13:23:56 +00:00
|
|
|
exit(0)
|
2019-04-18 03:08:35 +00:00
|
|
|
|
2019-11-12 11:39:49 +00:00
|
|
|
|
2019-04-15 16:31:08 +00:00
|
|
|
def parse_args():
|
|
|
|
parser = argparse.ArgumentParser(prog='restic_volume_backup')
|
|
|
|
parser.add_argument(
|
|
|
|
'action',
|
2019-04-17 18:20:52 +00:00
|
|
|
choices=['status', 'backup', 'start-backup-process'],
|
2019-04-15 16:31:08 +00:00
|
|
|
)
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
|
|
|
2019-04-13 17:04:54 +00:00
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|