backup-docker-to-local 1.1.0__tar.gz → 1.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {backup_docker_to_local-1.1.0/src/backup_docker_to_local.egg-info → backup_docker_to_local-1.1.1}/PKG-INFO +1 -1
  2. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/pyproject.toml +1 -1
  3. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1/src/backup_docker_to_local.egg-info}/PKG-INFO +1 -1
  4. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/backup/app.py +29 -17
  5. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/backup/db.py +21 -13
  6. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/LICENSE +0 -0
  7. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/README.md +0 -0
  8. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/setup.cfg +0 -0
  9. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/backup_docker_to_local.egg-info/SOURCES.txt +0 -0
  10. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/backup_docker_to_local.egg-info/dependency_links.txt +0 -0
  11. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/backup_docker_to_local.egg-info/entry_points.txt +0 -0
  12. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/backup_docker_to_local.egg-info/requires.txt +0 -0
  13. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/backup_docker_to_local.egg-info/top_level.txt +0 -0
  14. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/__init__.py +0 -0
  15. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/backup/__init__.py +0 -0
  16. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/backup/__main__.py +0 -0
  17. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/backup/cli.py +0 -0
  18. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/backup/compose.py +0 -0
  19. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/backup/docker.py +0 -0
  20. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/backup/shell.py +0 -0
  21. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/backup/volume.py +0 -0
  22. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/restore/__init__.py +0 -0
  23. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/restore/__main__.py +0 -0
  24. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/restore/db/__init__.py +0 -0
  25. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/restore/db/mariadb.py +0 -0
  26. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/restore/db/postgres.py +0 -0
  27. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/restore/files.py +0 -0
  28. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/restore/paths.py +0 -0
  29. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/restore/run.py +0 -0
  30. {backup_docker_to_local-1.1.0 → backup_docker_to_local-1.1.1}/src/baudolo/seed/__main__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: backup-docker-to-local
3
- Version: 1.1.0
3
+ Version: 1.1.1
4
4
  Summary: Backup Docker volumes to local with rsync and optional DB dumps.
5
5
  Author: Kevin Veen-Birkenbach
6
6
  License: AGPL-3.0-or-later
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "backup-docker-to-local"
7
- version = "1.1.0"
7
+ version = "1.1.1"
8
8
  description = "Backup Docker volumes to local with rsync and optional DB dumps."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: backup-docker-to-local
3
- Version: 1.1.0
3
+ Version: 1.1.1
4
4
  Summary: Backup Docker volumes to local with rsync and optional DB dumps.
5
5
  Author: Kevin Veen-Birkenbach
6
6
  License: AGPL-3.0-or-later
@@ -72,28 +72,27 @@ def requires_stop(containers: list[str], images_no_stop_required: list[str]) ->
72
72
  return True
73
73
  return False
74
74
 
75
-
76
75
  def backup_mariadb_or_postgres(
77
76
  *,
78
77
  container: str,
79
78
  volume_dir: str,
80
79
  databases_df: "pandas.DataFrame",
81
80
  database_containers: list[str],
82
- ) -> bool:
81
+ ) -> tuple[bool, bool]:
83
82
  """
84
- Returns True if the container is a DB container we handled.
83
+ Returns (is_db_container, dumped_any)
85
84
  """
86
85
  for img in ["mariadb", "postgres"]:
87
86
  if has_image(container, img):
88
- backup_database(
87
+ dumped = backup_database(
89
88
  container=container,
90
89
  volume_dir=volume_dir,
91
90
  db_type=img,
92
91
  databases_df=databases_df,
93
92
  database_containers=database_containers,
94
93
  )
95
- return True
96
- return False
94
+ return True, dumped
95
+ return False, False
97
96
 
98
97
 
99
98
  def _backup_dumps_for_volume(
@@ -102,21 +101,26 @@ def _backup_dumps_for_volume(
102
101
  vol_dir: str,
103
102
  databases_df: "pandas.DataFrame",
104
103
  database_containers: list[str],
105
- ) -> bool:
104
+ ) -> tuple[bool, bool]:
106
105
  """
107
- Create DB dumps for any mariadb/postgres containers attached to this volume.
108
- Returns True if at least one dump was produced.
106
+ Returns (found_db_container, dumped_any)
109
107
  """
108
+ found_db = False
110
109
  dumped_any = False
110
+
111
111
  for c in containers:
112
- if backup_mariadb_or_postgres(
112
+ is_db, dumped = backup_mariadb_or_postgres(
113
113
  container=c,
114
114
  volume_dir=vol_dir,
115
115
  databases_df=databases_df,
116
116
  database_containers=database_containers,
117
- ):
117
+ )
118
+ if is_db:
119
+ found_db = True
120
+ if dumped:
118
121
  dumped_any = True
119
- return dumped_any
122
+
123
+ return found_db, dumped_any
120
124
 
121
125
 
122
126
  def main() -> int:
@@ -137,18 +141,26 @@ def main() -> int:
137
141
  containers = containers_using_volume(volume_name)
138
142
 
139
143
  vol_dir = create_volume_directory(version_dir, volume_name)
140
-
141
- # Old behavior: DB dumps are additional to file backups.
142
- _backup_dumps_for_volume(
144
+
145
+ found_db, dumped_any = _backup_dumps_for_volume(
143
146
  containers=containers,
144
147
  vol_dir=vol_dir,
145
148
  databases_df=databases_df,
146
149
  database_containers=args.database_containers,
147
150
  )
148
151
 
149
- # dump-only: skip ALL file rsync backups
152
+ # dump-only logic:
150
153
  if args.dump_only:
151
- continue
154
+ if found_db and not dumped_any:
155
+ print(
156
+ f"WARNING: dump-only requested but no DB dump was produced for DB volume '{volume_name}'. Falling back to file backup.",
157
+ flush=True,
158
+ )
159
+ # continue to file backup below
160
+ else:
161
+ # keep old behavior: skip file backups
162
+ continue
163
+
152
164
 
153
165
  # skip file backup if all linked containers are ignored
154
166
  if volume_is_fully_ignored(containers, args.images_no_backup_required):
@@ -3,9 +3,8 @@ from __future__ import annotations
3
3
  import os
4
4
  import pathlib
5
5
  import re
6
-
7
- import pandas
8
6
  import logging
7
+ import pandas
9
8
 
10
9
  from .shell import BackupException, execute_shell_command
11
10
 
@@ -18,9 +17,7 @@ def get_instance(container: str, database_containers: list[str]) -> str:
18
17
  return re.split(r"(_|-)(database|db|postgres)", container)[0]
19
18
 
20
19
 
21
- def fallback_pg_dumpall(
22
- container: str, username: str, password: str, out_file: str
23
- ) -> None:
20
+ def fallback_pg_dumpall(container: str, username: str, password: str, out_file: str) -> None:
24
21
  cmd = (
25
22
  f"PGPASSWORD={password} docker exec -i {container} "
26
23
  f"pg_dumpall -U {username} -h localhost > {out_file}"
@@ -35,20 +32,25 @@ def backup_database(
35
32
  db_type: str,
36
33
  databases_df: "pandas.DataFrame",
37
34
  database_containers: list[str],
38
- ) -> None:
35
+ ) -> bool:
36
+ """
37
+ Returns True if at least one dump file was produced, else False.
38
+ """
39
39
  instance_name = get_instance(container, database_containers)
40
40
  entries = databases_df.loc[databases_df["instance"] == instance_name]
41
41
  if entries.empty:
42
- log.warning("No entry found for instance '%s'", instance_name)
43
- return
42
+ log.warning("No entry found for instance '%s' (skipping DB dump)", instance_name)
43
+ return False
44
44
 
45
45
  out_dir = os.path.join(volume_dir, "sql")
46
46
  pathlib.Path(out_dir).mkdir(parents=True, exist_ok=True)
47
47
 
48
- for row in entries.iloc:
49
- db_name = row["database"]
50
- user = row["username"]
51
- password = row["password"]
48
+ produced = False
49
+
50
+ for row in entries.itertuples(index=False):
51
+ db_name = row.database
52
+ user = row.username
53
+ password = row.password
52
54
 
53
55
  dump_file = os.path.join(out_dir, f"{db_name}.backup.sql")
54
56
 
@@ -58,13 +60,15 @@ def backup_database(
58
60
  f"-u {user} -p{password} {db_name} > {dump_file}"
59
61
  )
60
62
  execute_shell_command(cmd)
63
+ produced = True
61
64
  continue
62
65
 
63
66
  if db_type == "postgres":
64
67
  cluster_file = os.path.join(out_dir, f"{instance_name}.cluster.backup.sql")
68
+
65
69
  if not db_name:
66
70
  fallback_pg_dumpall(container, user, password, cluster_file)
67
- return
71
+ return True
68
72
 
69
73
  try:
70
74
  cmd = (
@@ -72,6 +76,7 @@ def backup_database(
72
76
  f"pg_dump -U {user} -d {db_name} -h localhost > {dump_file}"
73
77
  )
74
78
  execute_shell_command(cmd)
79
+ produced = True
75
80
  except BackupException as e:
76
81
  print(f"pg_dump failed: {e}", flush=True)
77
82
  print(
@@ -79,4 +84,7 @@ def backup_database(
79
84
  flush=True,
80
85
  )
81
86
  fallback_pg_dumpall(container, user, password, cluster_file)
87
+ produced = True
82
88
  continue
89
+
90
+ return produced