#!/usr/bin/env python3 import json import os from pathlib import Path from typing import Iterable import click import docker from docker.client import DockerClient from docker.errors import ContainerError from docker.models.containers import Container from rich.console import Console from rich.highlighter import NullHighlighter console = Console(highlighter=NullHighlighter()) print = console.print client = docker.from_env() def get_project_containers(client: DockerClient, project_name: str): return client.containers.list( all=True, filters={'label': [f"com.docker.compose.project={project_name}"]} ) def compose_start(client: DockerClient, project_name: str): print(f' DOCKER COMPOSE START {project_name} '.center(50, '=')) for con in get_project_containers(client, project_name): try: print(f'Starting {con.name}...'.ljust(30), end='') con.start() except Exception as e: print('Failed') console.print_exception(e) else: print('[green]Done[/]') def compose_stop(client: DockerClient, project_name: str): print(f' DOCKER COMPOSE STOP {project_name} '.center(50, '=')) for con in get_project_containers(client, project_name): try: print(f'Stopping {con.name}...'.ljust(30), end='') con.stop() except Exception as e: print('Failed') console.print_exception(e) else: print('[green]Done[/]') @click.command() @click.argument('data_dir', type=click.Path(exists=True, file_okay=False, resolve_path=True, path_type=Path)) @click.argument('repo', type=click.Path(exists=True, file_okay=False, resolve_path=True, path_type=Path), envvar='RESTIC_REPOSITORY') @click.option('-p', '--project') def run_backup_container(data_dir: Path, repo: Path, project: str): compose_stop(client, project_name=project) env = { 'RESTIC_REPOSITORY': '/repo', 'RESTIC_PASSWORD': os.environ['RESTIC_PASSWORD'] } volumes = { "/var/run/docker.sock": { "bind": "/var/run/docker.sock", "mode": "rw" }, data_dir.as_posix(): { "bind": '/data', "mode": "rw" }, repo.as_posix(): { "bind": '/repo', "mode": "rw" }, '/etc/localtime': { 'bind': '/etc/localtime', 'mode': 'ro' }, '/etc/timezone': { 'bind': '/etc/timezone', 'mode': 'ro' } } # print(json.dumps(volumes, indent=4)) print(f'Backing up\n{data_dir}\n to\n{repo}') try: resp = client.containers.run( image='restic/restic:latest', remove=True, hostname=os.environ['HOSTNAME'], environment=env, volumes=volumes, command='backup /data --dry-run' ).decode() print(resp) except ContainerError as e: print(e.stderr.decode()) finally: compose_start(client, project_name=project) if __name__ == '__main__': run_backup_container()