2022-01-23 13:01:49 +01:00
#!/bin/python
# Backups volumes of running containers
#
2022-01-23 17:20:42 +01:00
import subprocess , os , sys , pathlib , csv , pandas
2022-01-23 13:01:49 +01:00
from datetime import datetime
def bash ( command ) :
2022-01-23 17:20:42 +01:00
print ( command ) ;
2022-01-23 15:52:31 +01:00
process = subprocess . Popen ( [ command ] , stdout = subprocess . PIPE , stderr = subprocess . PIPE , shell = True )
out , err = process . communicate ( )
stdout = out . splitlines ( )
2022-01-23 14:04:38 +01:00
output = [ ]
for line in stdout :
output . append ( line . decode ( " utf-8 " ) )
2022-01-23 15:52:31 +01:00
if process . wait ( ) > bool ( 0 ) :
print ( command , out , err ) ;
raise Exception ( " Error is greater then 0 " )
2022-01-23 14:04:38 +01:00
return output
def print_bash ( command ) :
output = bash ( command )
print ( list_to_string ( output ) )
return output
2022-01-23 13:01:49 +01:00
def list_to_string ( list ) :
2022-01-23 14:04:38 +01:00
return str ( ' ' . join ( list ) ) ;
2022-01-23 13:01:49 +01:00
print ( ' start backup routine... ' )
print ( ' start volume backups... ' )
backup_time = datetime . now ( ) . strftime ( " % Y % m %d % H % M % S " )
backups_folder = ' /Backups/ '
2022-01-23 22:07:29 +01:00
dirname = os . path . dirname ( __file__ )
repository_name = os . path . basename ( dirname )
print ( ' load connection data... ' ) ;
databases = pandas . read_csv ( dirname + " /databases.csv " , sep = " ; " ) ;
2022-01-23 14:04:38 +01:00
machine_id = bash ( " sha256sum /etc/machine-id " ) [ 0 ] [ 0 : 64 ]
2022-01-23 13:01:49 +01:00
backup_repository_folder = backups_folder + machine_id + " / " + repository_name + " / "
2022-01-23 14:04:38 +01:00
volume_names = bash ( " docker volume ls --format ' {{ .Name}} ' " )
2022-01-23 13:01:49 +01:00
for volume_name in volume_names :
print ( ' start backup routine for volume: ' + volume_name ) ;
2022-01-23 14:04:38 +01:00
containers = bash ( " docker ps --filter volume= \" " + volume_name + " \" --format ' {{ .Names}} ' " )
2022-01-23 13:01:49 +01:00
if len ( containers ) == 0 :
print ( ' skipped due to no running containers using this volume. ' ) ;
else :
2022-01-23 15:52:31 +01:00
container = containers [ 0 ]
source_path_command = " docker inspect --format \" {{ range .Mounts }} {{ if eq .Type \\ \" volume \\ \" }} {{ if eq .Name \\ \" " + volume_name + " \\ \" }} {{ println .Destination }} {{ end }} {{ end }} {{ end }} \" \" " + container + " \" "
source_path_command_result_filtered = list ( filter ( None , bash ( source_path_command ) ) )
for source_path in source_path_command_result_filtered :
2022-01-23 14:04:38 +01:00
destination_path = backup_repository_folder + " latest/ " + volume_name
log_path = backup_repository_folder + " log.txt "
backup_dir_path = backup_repository_folder + " diffs/ " + backup_time + " / " + volume_name
2022-01-23 17:20:42 +01:00
databases_entries = databases . loc [ databases [ ' container ' ] == container ] ;
if len ( databases_entries ) == 1 :
2022-01-23 20:55:09 +01:00
print ( " Backup database... " )
sql_destination_path = destination_path + " /sql "
sql_backup_dir_path = backup_dir_path + " /sql "
2022-01-23 17:20:42 +01:00
sql_destination_dir_file_path = sql_destination_path + " /backup.sql "
2022-01-23 20:55:09 +01:00
pathlib . Path ( sql_destination_path ) . mkdir ( parents = True , exist_ok = True )
pathlib . Path ( sql_backup_dir_path ) . mkdir ( parents = True , exist_ok = True )
database_entry = databases_entries . iloc [ 0 ] ;
2022-01-23 17:20:42 +01:00
database_backup_command = " docker exec " + database_entry [ " container " ] + " /usr/bin/mysqldump -u " + database_entry [ " username " ] + " -p " + database_entry [ " password " ] + " " + database_entry [ " database " ] + " > " + sql_destination_dir_file_path
print_bash ( database_backup_command )
print_bash ( " cp -v " + sql_destination_dir_file_path + " " + sql_backup_dir_path )
2022-01-23 14:04:38 +01:00
else :
2022-01-23 20:55:09 +01:00
print ( " Backup files... " )
files_destination_path = destination_path + " /files "
files_backup_dir_path = backup_dir_path + " /files "
pathlib . Path ( files_backup_dir_path ) . mkdir ( parents = True , exist_ok = True )
pathlib . Path ( files_destination_path ) . mkdir ( parents = True , exist_ok = True )
print ( " stop containers... " ) ;
2022-01-23 17:20:42 +01:00
print_bash ( " docker stop " + list_to_string ( containers ) )
print_bash ( " docker run --rm --volumes-from " + container + " -v " + backups_folder + " : " + backups_folder + " \" kevinveenbirkenbach/alpine-rsync \" sh -c \" rsync -abP --delete --delete-excluded --log-file= " + log_path + " --backup-dir= " + files_backup_dir_path + " ' " + source_path + " / ' " + files_destination_path + " \" " )
2022-01-23 20:55:09 +01:00
print ( " start containers... " )
2022-01-23 17:20:42 +01:00
print_bash ( " docker start " + list_to_string ( containers ) )
2022-01-23 14:04:38 +01:00
print ( " end backup routine for volume: " + volume_name )
2022-01-23 13:01:49 +01:00
print ( ' finished volume backups. ' )
print ( ' restart docker service... ' )
2022-01-23 14:04:38 +01:00
print_bash ( " systemctl restart docker " )
2022-01-23 13:01:49 +01:00
print ( ' finished backup routine. ' )