Merge pull request #26 from jannikw/project-names
Allow grouping of backup directories by project name
This commit is contained in:
commit
93f080d5b3
|
@ -5,6 +5,7 @@
|
||||||
# DOCKER_CERT_PATH=''
|
# DOCKER_CERT_PATH=''
|
||||||
|
|
||||||
SWARM_MODE=true
|
SWARM_MODE=true
|
||||||
|
INCLUDE_PROJECT_NAME=false
|
||||||
|
|
||||||
RESTIC_REPOSITORY=/restic_data
|
RESTIC_REPOSITORY=/restic_data
|
||||||
RESTIC_PASSWORD=password
|
RESTIC_PASSWORD=password
|
||||||
|
|
|
@ -66,6 +66,7 @@ def status(config, containers):
|
||||||
logger.info("Status for compose project '%s'", containers.project_name)
|
logger.info("Status for compose project '%s'", containers.project_name)
|
||||||
logger.info("Repository: '%s'", config.repository)
|
logger.info("Repository: '%s'", config.repository)
|
||||||
logger.info("Backup currently running?: %s", containers.backup_process_running)
|
logger.info("Backup currently running?: %s", containers.backup_process_running)
|
||||||
|
logger.info("Include project name in backup path?: %s", utils.is_true(config.include_project_name))
|
||||||
logger.info("Checking docker availability")
|
logger.info("Checking docker availability")
|
||||||
|
|
||||||
utils.list_containers()
|
utils.list_containers()
|
||||||
|
@ -91,12 +92,12 @@ def status(config, containers):
|
||||||
|
|
||||||
if container.volume_backup_enabled:
|
if container.volume_backup_enabled:
|
||||||
for mount in container.filter_mounts():
|
for mount in container.filter_mounts():
|
||||||
logger.info(' - volume: %s', mount.source)
|
logger.info(' - volume: %s -> %s', mount.source, container.get_volume_backup_destination(mount, '/volumes'))
|
||||||
|
|
||||||
if container.database_backup_enabled:
|
if container.database_backup_enabled:
|
||||||
instance = container.instance
|
instance = container.instance
|
||||||
ping = instance.ping()
|
ping = instance.ping()
|
||||||
logger.info(' - %s (is_ready=%s)', instance.container_type, ping == 0)
|
logger.info(' - %s (is_ready=%s) -> %s', instance.container_type, ping == 0, instance.backup_destination_path())
|
||||||
if ping != 0:
|
if ping != 0:
|
||||||
logger.error("Database '%s' in service %s cannot be reached",
|
logger.error("Database '%s' in service %s cannot be reached",
|
||||||
instance.container_type, container.service_name)
|
instance.container_type, container.service_name)
|
||||||
|
|
|
@ -13,6 +13,7 @@ class Config:
|
||||||
self.cron_schedule = os.environ.get('CRON_SCHEDULE') or self.default_crontab_schedule
|
self.cron_schedule = os.environ.get('CRON_SCHEDULE') or self.default_crontab_schedule
|
||||||
self.cron_command = os.environ.get('CRON_COMMAND') or self.default_backup_command
|
self.cron_command = os.environ.get('CRON_COMMAND') or self.default_backup_command
|
||||||
self.swarm_mode = os.environ.get('SWARM_MODE') or False
|
self.swarm_mode = os.environ.get('SWARM_MODE') or False
|
||||||
|
self.include_project_name = os.environ.get('INCLUDE_PROJECT_NAME') or False
|
||||||
|
|
||||||
# Log
|
# Log
|
||||||
self.log_level = os.environ.get('LOG_LEVEL')
|
self.log_level = os.environ.get('LOG_LEVEL')
|
||||||
|
|
|
@ -224,12 +224,26 @@ class Container:
|
||||||
volumes = {}
|
volumes = {}
|
||||||
for mount in mounts:
|
for mount in mounts:
|
||||||
volumes[mount.source] = {
|
volumes[mount.source] = {
|
||||||
'bind': str(Path(source_prefix) / self.service_name / Path(utils.strip_root(mount.destination))),
|
'bind': self.get_volume_backup_destination(mount, source_prefix),
|
||||||
'mode': mode,
|
'mode': mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
return volumes
|
return volumes
|
||||||
|
|
||||||
|
def get_volume_backup_destination(self, mount, source_prefix) -> str:
|
||||||
|
"""Get the destination path for backups of the given mount"""
|
||||||
|
destination = Path(source_prefix)
|
||||||
|
|
||||||
|
if utils.is_true(config.include_project_name):
|
||||||
|
project_name = self.project_name
|
||||||
|
if project_name != '':
|
||||||
|
destination /= project_name
|
||||||
|
|
||||||
|
destination /= self.service_name
|
||||||
|
destination /= Path(utils.strip_root(mount.destination))
|
||||||
|
|
||||||
|
return str(destination)
|
||||||
|
|
||||||
def get_credentials(self) -> dict:
|
def get_credentials(self) -> dict:
|
||||||
"""dict: get credentials for the service"""
|
"""dict: get credentials for the service"""
|
||||||
raise NotImplementedError("Base container class don't implement this")
|
raise NotImplementedError("Base container class don't implement this")
|
||||||
|
@ -242,6 +256,10 @@ class Container:
|
||||||
"""Back up this service"""
|
"""Back up this service"""
|
||||||
raise NotImplementedError("Base container class don't implement this")
|
raise NotImplementedError("Base container class don't implement this")
|
||||||
|
|
||||||
|
def backup_destination_path(self) -> str:
|
||||||
|
"""Return the path backups will be saved at"""
|
||||||
|
raise NotImplementedError("Base container class don't implement this")
|
||||||
|
|
||||||
def dump_command(self) -> list:
|
def dump_command(self) -> list:
|
||||||
"""list: create a dump command restic and use to send data through stdin"""
|
"""list: create a dump command restic and use to send data through stdin"""
|
||||||
raise NotImplementedError("Base container class don't implement this")
|
raise NotImplementedError("Base container class don't implement this")
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from restic_compose_backup.containers import Container
|
from restic_compose_backup.containers import Container
|
||||||
from restic_compose_backup.config import Config
|
from restic_compose_backup.config import config, Config
|
||||||
from restic_compose_backup import (
|
from restic_compose_backup import (
|
||||||
commands,
|
commands,
|
||||||
restic,
|
restic,
|
||||||
|
@ -48,10 +50,23 @@ class MariadbContainer(Container):
|
||||||
with utils.environment('MYSQL_PWD', creds['password']):
|
with utils.environment('MYSQL_PWD', creds['password']):
|
||||||
return restic.backup_from_stdin(
|
return restic.backup_from_stdin(
|
||||||
config.repository,
|
config.repository,
|
||||||
f'/databases/{self.service_name}/all_databases.sql',
|
self.backup_destination_path(),
|
||||||
self.dump_command(),
|
self.dump_command(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def backup_destination_path(self) -> str:
|
||||||
|
destination = Path("/databases")
|
||||||
|
|
||||||
|
if utils.is_true(config.include_project_name):
|
||||||
|
project_name = self.project_name
|
||||||
|
if project_name != "":
|
||||||
|
destination /= project_name
|
||||||
|
|
||||||
|
destination /= self.service_name
|
||||||
|
destination /= "all_databases.sql"
|
||||||
|
|
||||||
|
return destination
|
||||||
|
|
||||||
|
|
||||||
class MysqlContainer(Container):
|
class MysqlContainer(Container):
|
||||||
container_type = 'mysql'
|
container_type = 'mysql'
|
||||||
|
@ -94,10 +109,23 @@ class MysqlContainer(Container):
|
||||||
with utils.environment('MYSQL_PWD', creds['password']):
|
with utils.environment('MYSQL_PWD', creds['password']):
|
||||||
return restic.backup_from_stdin(
|
return restic.backup_from_stdin(
|
||||||
config.repository,
|
config.repository,
|
||||||
f'/databases/{self.service_name}/all_databases.sql',
|
self.backup_destination_path(),
|
||||||
self.dump_command(),
|
self.dump_command(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def backup_destination_path(self) -> str:
|
||||||
|
destination = Path("/databases")
|
||||||
|
|
||||||
|
if utils.is_true(config.include_project_name):
|
||||||
|
project_name = self.project_name
|
||||||
|
if project_name != "":
|
||||||
|
destination /= project_name
|
||||||
|
|
||||||
|
destination /= self.service_name
|
||||||
|
destination /= "all_databases.sql"
|
||||||
|
|
||||||
|
return destination
|
||||||
|
|
||||||
|
|
||||||
class PostgresContainer(Container):
|
class PostgresContainer(Container):
|
||||||
container_type = 'postgres'
|
container_type = 'postgres'
|
||||||
|
@ -141,6 +169,19 @@ class PostgresContainer(Container):
|
||||||
with utils.environment('PGPASSWORD', creds['password']):
|
with utils.environment('PGPASSWORD', creds['password']):
|
||||||
return restic.backup_from_stdin(
|
return restic.backup_from_stdin(
|
||||||
config.repository,
|
config.repository,
|
||||||
f"/databases/{self.service_name}/{creds['database']}.sql",
|
self.backup_destination_path(),
|
||||||
self.dump_command(),
|
self.dump_command(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def backup_destination_path(self) -> str:
|
||||||
|
destination = Path("/databases")
|
||||||
|
|
||||||
|
if utils.is_true(config.include_project_name):
|
||||||
|
project_name = self.project_name
|
||||||
|
if project_name != "":
|
||||||
|
destination /= project_name
|
||||||
|
|
||||||
|
destination /= self.service_name
|
||||||
|
destination /= f"{self.get_credentials()['database']}.sql"
|
||||||
|
|
||||||
|
return destination
|
||||||
|
|
Loading…
Reference in New Issue