21 Commits

Author SHA1 Message Date
7e8c598eb5 Update .env.sample
All checks were successful
continuous-integration/drone/pr Build is passing
2024-08-11 03:33:49 +00:00
cc049b858b README: new image location
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-05 16:30:40 +02:00
b7bc8ed58f fix: ignore none swarm container #52
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-05 14:41:50 +02:00
68e37f5c23 Merge pull request 'Add dockerfile, and compose.yml to use it' (#49) from feature/dockerfile into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #49
2024-06-01 03:36:07 +00:00
3wc
4d39d84733 Switch ENTRYPOINT to try to resolve loop on start
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-06-01 03:35:52 +00:00
3wc
e5b9bc0446 Update requirements 2024-06-01 03:35:52 +00:00
3wc
ec4c4509dc Make entrypoint executable 2024-06-01 03:35:52 +00:00
3wc
26162a9e38 Add --break-system-packages, surely we don't need a virtualenv 2024-06-01 03:35:52 +00:00
3wc
bd581fd8d7 Move entrypoint script into Docker image 2024-06-01 03:35:52 +00:00
3wc
e77432e3ab Move /entrypoint.sh to Dockerfile 2024-06-01 03:35:52 +00:00
3wc
001a654e37 Remove redundant stuff from entrypoint 2024-06-01 03:35:52 +00:00
3wc
c5574edc54 Whoops, wrong image 2024-06-01 03:35:52 +00:00
3wc
50e4d68717 Switch to backup-bot-two image 2024-06-01 03:35:52 +00:00
3wc
c7830ceb6f Whoops skip shellcheck 2024-06-01 03:35:52 +00:00
3wc
b6f859efbb Reinstate Docker image 2024-06-01 03:35:52 +00:00
7f14698824 change loglever to warning for not running container
Some checks failed
continuous-integration/drone/push Build is failing
2024-05-06 11:31:40 +02:00
2a9a98172f Add debug infos
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-30 15:27:17 +02:00
282215cf9c Add debug infos
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-30 14:59:59 +02:00
ae7a14b6f1 Fix usage of RESTIC_REPOSITORY_FILE #51
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-30 14:51:46 +02:00
8acdb20e5b Fix loghandler
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-29 14:18:32 +02:00
5582744073 Fix usage of RESTIC_REPOSITORY_FILE #51 2024-04-29 14:16:13 +02:00
3 changed files with 18 additions and 9 deletions

View File

@ -4,6 +4,8 @@ SECRET_RESTIC_PASSWORD_VERSION=v1
COMPOSE_FILE=compose.yml
DOMAIN=backup-bot-two.example.com
RESTIC_REPOSITORY=/backups/restic
CRON_SCHEDULE='30 3 * * *'

View File

@ -10,7 +10,7 @@ Automatically take backups from all volumes of running Docker Swarm services and
* **Category**: Utilities
* **Status**: 0, work-in-progress
* **Image**: [`thecoopcloud/backup-bot-two`](https://hub.docker.com/r/thecoopcloud/backup-bot-two), 4, upstream
* **Image**: [`git.coopcloud.tech/coop-cloud/backup-bot-two`](https://git.coopcloud.tech/coop-cloud/-/packages/container/backup-bot-two), 4, upstream
* **Healthcheck**: No
* **Backups**: N/A
* **Email**: N/A

View File

@ -42,7 +42,7 @@ sys.excepthook = handle_exception
@click.option('-l', '--log', 'loglevel')
@click.option('-m', '--machine-logs', 'machine_logs', is_flag=True)
@click.option('service', '--host', '-h', envvar='SERVICE')
@click.option('repository', '--repo', '-r', envvar='RESTIC_REPOSITORY', required=True)
@click.option('repository', '--repo', '-r', envvar='RESTIC_REPOSITORY')
def cli(loglevel, service, repository, machine_logs):
global SERVICE
if service:
@ -54,21 +54,25 @@ def cli(loglevel, service, repository, machine_logs):
if not isinstance(numeric_level, int):
raise ValueError('Invalid log level: %s' % loglevel)
logger.setLevel(numeric_level)
logHandler = logging.StreamHandler()
if machine_logs:
logHandler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter(
"%(levelname)s %(filename)s %(lineno)s %(process)d %(message)s", rename_fields={"levelname": "message_type"})
logHandler.setFormatter(formatter)
logger.addHandler(logHandler)
logger.addHandler(logHandler)
export_secrets()
init_repo()
def init_repo():
repo = os.environ['RESTIC_REPOSITORY']
if repo:= os.environ.get('RESTIC_REPOSITORY_FILE'):
# RESTIC_REPOSITORY_FILE and RESTIC_REPOSITORY are mutually exclusive
del os.environ['RESTIC_REPOSITORY']
else:
repo = os.environ['RESTIC_REPOSITORY']
restic.repository = repo
logger.debug(f"set restic repository location: {repo}")
restic.repository = repo
restic.password_file = '/var/run/secrets/restic_password'
try:
restic.cat.config()
@ -104,7 +108,7 @@ def create(retries):
def get_backup_cmds():
client = docker.from_env()
container_by_service = {
c.labels['com.docker.swarm.service.name']: c for c in client.containers.list()}
c.labels.get('com.docker.swarm.service.name'): c for c in client.containers.list()}
backup_paths = set()
backup_apps = set()
pre_commands = {}
@ -139,14 +143,14 @@ def copy_secrets(apps):
os.mkdir(SECRET_PATH)
client = docker.from_env()
container_by_service = {
c.labels['com.docker.swarm.service.name']: c for c in client.containers.list()}
c.labels.get('com.docker.swarm.service.name'): c for c in client.containers.list()}
services = client.services.list()
for s in services:
app_name = s.attrs['Spec']['Labels']['com.docker.stack.namespace']
if (app_name in apps and
(app_secs := s.attrs['Spec']['TaskTemplate']['ContainerSpec'].get('Secrets'))):
if not container_by_service.get(s.name):
logger.error(
logger.warning(
f"Container {s.name} is not running, secrets can not be copied.")
continue
container_id = container_by_service[s.name].id
@ -157,6 +161,7 @@ def copy_secrets(apps):
f"For the secret {sec['SecretName']} the file {src} does not exist for {s.name}")
continue
dst = SECRET_PATH + sec['SecretName']
logger.debug("Copy Secret {sec['SecretName']}")
copyfile(src, dst)
@ -184,6 +189,8 @@ def run_commands(commands):
def backup_volumes(backup_paths, apps, retries, dry_run=False):
while True:
try:
logger.info("Start volume backup")
logger.debug(backup_paths)
result = restic.backup(backup_paths, dry_run=dry_run, tags=apps)
logger.summary("backup finished", extra=result)
return