5
5
from datetime import datetime
6
6
from io import StringIO
7
7
from pathlib import Path
8
- from typing import Callable , Dict , Optional , Sequence
8
+ from typing import Callable , Dict , NamedTuple , Optional , Sequence
9
9
10
10
import docker
11
11
import pycron
17
17
BackupCandidate = Callable [[Container ], str ]
18
18
19
19
20
+ class BackupProvider (NamedTuple ):
21
+ patterns : list [str ]
22
+ backup_method : BackupCandidate
23
+ file_extension : str
24
+
25
+
20
26
def get_container_env (container : Container ) -> Dict [str , Optional [str ]]:
21
27
"""
22
28
Get all environment variables from a container.
@@ -45,23 +51,29 @@ def backup_mysql(container: Container) -> str:
45
51
return f"bash -c 'mysqldump { auth } --all-databases'"
46
52
47
53
48
- BACKUP_MAPPING : Dict [str , BackupCandidate ] = {
49
- "postgres" : backup_psql ,
50
- "mysql" : backup_mysql ,
51
- "mariadb" : backup_mysql , # Basically the same thing
52
- "*/linuxserver/mariadb" : backup_mysql , # LSIO have their own MariaDB container
53
- }
54
+ BACKUP_PROVIDERS : list [BackupProvider ] = [
55
+ BackupProvider (
56
+ patterns = ["postgres" ], backup_method = backup_psql , file_extension = "sql"
57
+ ),
58
+ BackupProvider (
59
+ patterns = ["mysql" , "mariadb" , "*/linuxserver/mariadb" ],
60
+ backup_method = backup_mysql ,
61
+ file_extension = "sql" ,
62
+ ),
63
+ ]
64
+
54
65
55
66
BACKUP_DIR = Path (os .environ .get ("BACKUP_DIR" , "/var/backups" ))
56
67
SCHEDULE = os .environ .get ("SCHEDULE" , "@daily" )
57
68
SHOW_PROGRESS = sys .stdout .isatty ()
58
69
59
70
60
- def get_backup_method (container_names : Sequence [str ]) -> Optional [BackupCandidate ]:
71
+ def get_backup_provider (container_names : Sequence [str ]) -> Optional [BackupProvider ]:
61
72
for name in container_names :
62
- for container_pattern , backup_candidate in BACKUP_MAPPING .items ():
63
- if fnmatch .fnmatch (name , container_pattern ):
64
- return backup_candidate
73
+ for provider in BACKUP_PROVIDERS :
74
+ for pattern in provider .patterns :
75
+ if fnmatch .fnmatch (name , pattern ):
76
+ return provider
65
77
66
78
return None
67
79
@@ -74,12 +86,12 @@ def backup(now: datetime) -> None:
74
86
75
87
for container in docker_client .containers .list ():
76
88
container_names = [tag .rsplit (":" , 1 )[0 ] for tag in container .image .tags ]
77
- backup_method = get_backup_method (container_names )
78
- if backup_method is None :
89
+ backup_provider = get_backup_provider (container_names )
90
+ if backup_provider is None :
79
91
continue
80
92
81
- backup_command = backup_method (container )
82
- backup_file = BACKUP_DIR / f"{ container .name } .sql "
93
+ backup_command = backup_provider . backup_method (container )
94
+ backup_file = BACKUP_DIR / f"{ container .name } .{ backup_provider . file_extension } "
83
95
_ , output = container .exec_run (backup_command , stream = True , demux = True )
84
96
85
97
with tqdm .wrapattr (
0 commit comments