dar-backup 0.6.14__py3-none-any.whl → 0.6.16__py3-none-any.whl
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.
- dar_backup/__about__.py +1 -1
- dar_backup/cleanup.py +31 -1
- dar_backup/dar_backup.py +44 -27
- dar_backup/util.py +1 -1
- {dar_backup-0.6.14.dist-info → dar_backup-0.6.16.dist-info}/METADATA +140 -24
- {dar_backup-0.6.14.dist-info → dar_backup-0.6.16.dist-info}/RECORD +9 -9
- {dar_backup-0.6.14.dist-info → dar_backup-0.6.16.dist-info}/WHEEL +0 -0
- {dar_backup-0.6.14.dist-info → dar_backup-0.6.16.dist-info}/entry_points.txt +0 -0
- {dar_backup-0.6.14.dist-info → dar_backup-0.6.16.dist-info}/licenses/LICENSE +0 -0
dar_backup/__about__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.6.
|
|
1
|
+
__version__ = "0.6.16"
|
dar_backup/cleanup.py
CHANGED
|
@@ -21,6 +21,7 @@ import subprocess
|
|
|
21
21
|
import sys
|
|
22
22
|
|
|
23
23
|
from datetime import datetime, timedelta
|
|
24
|
+
from inputimeout import inputimeout, TimeoutOccurred
|
|
24
25
|
from time import time
|
|
25
26
|
from typing import Dict, List, NamedTuple
|
|
26
27
|
|
|
@@ -156,6 +157,7 @@ def show_version():
|
|
|
156
157
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW, not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
157
158
|
See section 15 and section 16 in the supplied "LICENSE" file.''')
|
|
158
159
|
|
|
160
|
+
|
|
159
161
|
def main():
|
|
160
162
|
global logger
|
|
161
163
|
|
|
@@ -164,11 +166,12 @@ def main():
|
|
|
164
166
|
parser.add_argument('-c', '--config-file', '-c', type=str, help="Path to 'dar-backup.conf'", default='~/.config/dar-backup/dar-backup.conf')
|
|
165
167
|
parser.add_argument('-v', '--version', action='store_true', help="Show version information.")
|
|
166
168
|
parser.add_argument('--alternate-archive-dir', type=str, help="Cleanup in this directory instead of the default one.")
|
|
167
|
-
parser.add_argument('--cleanup-specific-archives', type=str, help="
|
|
169
|
+
parser.add_argument('--cleanup-specific-archives', type=str, help="Comma separated list of archives to cleanup")
|
|
168
170
|
parser.add_argument('-l', '--list', action='store_true', help="List available archives.")
|
|
169
171
|
parser.add_argument('--verbose', action='store_true', help="Print various status messages to screen")
|
|
170
172
|
parser.add_argument('--log-level', type=str, help="`debug` or `trace`, default is `info`", default="info")
|
|
171
173
|
parser.add_argument('--log-stdout', action='store_true', help='also print log messages to stdout')
|
|
174
|
+
parser.add_argument('--test-mode', action='store_true', help='Read envvars in order to run some pytest cases')
|
|
172
175
|
args = parser.parse_args()
|
|
173
176
|
|
|
174
177
|
args.config_file = os.path.expanduser(os.path.expandvars(args.config_file))
|
|
@@ -232,6 +235,33 @@ def main():
|
|
|
232
235
|
logger.info(f"Cleaning up specific archives: {args.cleanup_specific_archives}")
|
|
233
236
|
archive_names = args.cleanup_specific_archives.split(',')
|
|
234
237
|
for archive_name in archive_names:
|
|
238
|
+
if "_FULL_" in archive_name:
|
|
239
|
+
try:
|
|
240
|
+
try:
|
|
241
|
+
# used for pytest cases
|
|
242
|
+
if args.test_mode:
|
|
243
|
+
confirmation = os.environ.get("CLEANUP_TEST_DELETE_FULL")
|
|
244
|
+
if confirmation == None:
|
|
245
|
+
raise RuntimeError("envvar 'CLEANUP_TEST_DELETE_FULL' not set")
|
|
246
|
+
|
|
247
|
+
else:
|
|
248
|
+
confirmation = inputimeout(
|
|
249
|
+
prompt=f"Are you sure you want to delete the FULL archive '{archive_name}'? (yes/no): ",
|
|
250
|
+
timeout=30)
|
|
251
|
+
if confirmation == None:
|
|
252
|
+
continue
|
|
253
|
+
else:
|
|
254
|
+
confirmation = confirmation.strip().lower()
|
|
255
|
+
except TimeoutOccurred:
|
|
256
|
+
logger.info(f"Timeout waiting for confirmation for FULL archive: {archive_name}. Skipping deletion.")
|
|
257
|
+
continue
|
|
258
|
+
except KeyboardInterrupt:
|
|
259
|
+
logger.info(f"User interrupted confirmation for FULL archive: {archive_name}. Skipping deletion.")
|
|
260
|
+
continue
|
|
261
|
+
|
|
262
|
+
if confirmation != 'yes':
|
|
263
|
+
logger.info(f"User did not answer 'yes' to confirm deletion of FULL archive: {archive_name}. Skipping deletion.")
|
|
264
|
+
continue
|
|
235
265
|
logger.info(f"Deleting archive: {archive_name}")
|
|
236
266
|
delete_archive(config_settings.backup_dir, archive_name.strip(), args)
|
|
237
267
|
elif args.list:
|
dar_backup/dar_backup.py
CHANGED
|
@@ -34,7 +34,7 @@ from dar_backup.util import RestoreError
|
|
|
34
34
|
|
|
35
35
|
logger = None
|
|
36
36
|
|
|
37
|
-
def generic_backup(type: str, command: List[str], backup_file: str, backup_definition: str, darrc: str, config_settings: ConfigSettings, args: argparse.Namespace):
|
|
37
|
+
def generic_backup(type: str, command: List[str], backup_file: str, backup_definition: str, darrc: str, config_settings: ConfigSettings, args: argparse.Namespace) -> List[str]:
|
|
38
38
|
"""
|
|
39
39
|
Performs a backup using the 'dar' command.
|
|
40
40
|
|
|
@@ -54,10 +54,14 @@ def generic_backup(type: str, command: List[str], backup_file: str, backup_defin
|
|
|
54
54
|
config_settings (ConfigSettings): An instance of the ConfigSettings class.
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
|
|
58
57
|
Raises:
|
|
59
|
-
BackupError: If an error occurs during the backup process.
|
|
58
|
+
BackupError: If an error leading to a bad backup occurs during the backup process.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
List of tuples (<msg>, <exit_code>) of errors not considered critical enough for raising an exception
|
|
60
62
|
"""
|
|
63
|
+
result: List[tuple] = []
|
|
64
|
+
|
|
61
65
|
logger.info(f"===> Starting {type} backup for {backup_definition}")
|
|
62
66
|
logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
|
|
63
67
|
try:
|
|
@@ -75,7 +79,11 @@ def generic_backup(type: str, command: List[str], backup_file: str, backup_defin
|
|
|
75
79
|
if command_result.returncode == 0:
|
|
76
80
|
logger.info(f"Catalog for archive '{backup_file}' added successfully to its manager.")
|
|
77
81
|
else:
|
|
78
|
-
|
|
82
|
+
msg = f"Catalog for archive '{backup_file}' not added."
|
|
83
|
+
logger.error(msg)
|
|
84
|
+
result.append((msg, 1))
|
|
85
|
+
|
|
86
|
+
return result
|
|
79
87
|
|
|
80
88
|
except subprocess.CalledProcessError as e:
|
|
81
89
|
logger.error(f"Backup command failed: {e}")
|
|
@@ -83,7 +91,7 @@ def generic_backup(type: str, command: List[str], backup_file: str, backup_defin
|
|
|
83
91
|
except Exception as e:
|
|
84
92
|
logger.exception(f"Unexpected error during backup")
|
|
85
93
|
raise BackupError(f"Unexpected error during backup: {e}") from e
|
|
86
|
-
|
|
94
|
+
|
|
87
95
|
|
|
88
96
|
|
|
89
97
|
def find_files_with_paths(xml_doc: str):
|
|
@@ -184,7 +192,7 @@ def verify(args: argparse.Namespace, backup_file: str, backup_definition: str, c
|
|
|
184
192
|
"""
|
|
185
193
|
result = True
|
|
186
194
|
command = ['dar', '-t', backup_file, '-Q']
|
|
187
|
-
logger.
|
|
195
|
+
logger.debug(f"Running command: {' '.join(map(shlex.quote, command))}")
|
|
188
196
|
process = run_command(command, config_settings.command_timeout_secs)
|
|
189
197
|
if process.returncode == 0:
|
|
190
198
|
logger.info("Archive integrity test passed.")
|
|
@@ -208,8 +216,9 @@ def verify(args: argparse.Namespace, backup_file: str, backup_definition: str, c
|
|
|
208
216
|
root_path = None
|
|
209
217
|
for line in backup_definition_content:
|
|
210
218
|
line = line.strip()
|
|
211
|
-
|
|
212
|
-
|
|
219
|
+
match = re.match(r'^\s*-R\s+(.*)', line)
|
|
220
|
+
if match:
|
|
221
|
+
root_path = match.group(1).strip()
|
|
213
222
|
break
|
|
214
223
|
if root_path is None:
|
|
215
224
|
msg = f"No Root (-R) path found in the backup definition file: '{backup_definition}', restore verification skipped"
|
|
@@ -223,15 +232,15 @@ def verify(args: argparse.Namespace, backup_file: str, backup_definition: str, c
|
|
|
223
232
|
random_files = random.sample(files, no_files_verification)
|
|
224
233
|
for restored_file_path in random_files:
|
|
225
234
|
try:
|
|
226
|
-
logger.info(f"Restoring file: '{restored_file_path}' from backup to: '{config_settings.test_restore_dir}' for file comparing")
|
|
235
|
+
args.verbose and logger.info(f"Restoring file: '{restored_file_path}' from backup to: '{config_settings.test_restore_dir}' for file comparing")
|
|
227
236
|
command = ['dar', '-x', backup_file, '-g', restored_file_path.lstrip("/"), '-R', config_settings.test_restore_dir, '-Q', '-B', args.darrc, 'restore-options']
|
|
228
|
-
logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
|
|
237
|
+
args.verbose and logger.info(f"Running command: {' '.join(map(shlex.quote, command))}")
|
|
229
238
|
process = run_command(command, config_settings.command_timeout_secs)
|
|
230
239
|
if process.returncode != 0:
|
|
231
240
|
raise Exception(str(process))
|
|
232
241
|
|
|
233
242
|
if filecmp.cmp(os.path.join(config_settings.test_restore_dir, restored_file_path.lstrip("/")), os.path.join(root_path, restored_file_path.lstrip("/")), shallow=False):
|
|
234
|
-
logger.info(f"Success: file '{restored_file_path}' matches the original")
|
|
243
|
+
args.verbose and logger.info(f"Success: file '{restored_file_path}' matches the original")
|
|
235
244
|
else:
|
|
236
245
|
raise BackupError(f"Failure: file '{restored_file_path}' did not match the original")
|
|
237
246
|
except PermissionError:
|
|
@@ -295,11 +304,11 @@ def get_backed_up_files(backup_name: str, backup_dir: str):
|
|
|
295
304
|
Returns:
|
|
296
305
|
list: A list of file paths for all backed up files in the DAR archive.
|
|
297
306
|
"""
|
|
298
|
-
logger.debug(f"Getting backed up files from DAR archive
|
|
307
|
+
logger.debug(f"Getting backed up files in xml from DAR archive: '{backup_name}'")
|
|
299
308
|
backup_path = os.path.join(backup_dir, backup_name)
|
|
300
309
|
try:
|
|
301
310
|
command = ['dar', '-l', backup_path, '-am', '-as', "-Txml" , '-Q']
|
|
302
|
-
logger.
|
|
311
|
+
logger.debug(f"Running command: {' '.join(map(shlex.quote, command))}")
|
|
303
312
|
command_result = run_command(command)
|
|
304
313
|
# Parse the XML data
|
|
305
314
|
file_paths = find_files_with_paths(command_result.stdout)
|
|
@@ -383,7 +392,7 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
|
|
|
383
392
|
backup_type: Type of backup (FULL, DIFF, INCR).
|
|
384
393
|
|
|
385
394
|
Returns:
|
|
386
|
-
|
|
395
|
+
List[tuples] - each tuple consists of (<str message>, <exit code>)
|
|
387
396
|
"""
|
|
388
397
|
backup_definitions = []
|
|
389
398
|
results: List[tuple] = []
|
|
@@ -443,7 +452,8 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
|
|
|
443
452
|
command = create_backup_command(backup_type, backup_file, args.darrc, backup_definition_path, latest_base_backup)
|
|
444
453
|
|
|
445
454
|
# Perform backup
|
|
446
|
-
generic_backup(backup_type, command, backup_file, backup_definition_path, args.darrc, config_settings, args)
|
|
455
|
+
backup_result = generic_backup(backup_type, command, backup_file, backup_definition_path, args.darrc, config_settings, args)
|
|
456
|
+
results.extend(backup_result)
|
|
447
457
|
|
|
448
458
|
logger.info("Starting verification...")
|
|
449
459
|
verify_result = verify(args, backup_file, backup_definition_path, config_settings)
|
|
@@ -458,7 +468,7 @@ def perform_backup(args: argparse.Namespace, config_settings: ConfigSettings, ba
|
|
|
458
468
|
logger.info("par2 files completed successfully.")
|
|
459
469
|
|
|
460
470
|
except Exception as e:
|
|
461
|
-
results.
|
|
471
|
+
results.append((repr(e), 1))
|
|
462
472
|
logger.exception(f"Error during {backup_type} backup process, continuing to next backup definition.")
|
|
463
473
|
|
|
464
474
|
logger.trace(f"perform_backup() results[]: {results}")
|
|
@@ -519,8 +529,14 @@ def filter_darrc_file(darrc_path):
|
|
|
519
529
|
The filtered version is stored in a uniquely named file in the home directory of the user running the script.
|
|
520
530
|
The file permissions are set to 440.
|
|
521
531
|
|
|
522
|
-
:
|
|
523
|
-
|
|
532
|
+
Params:
|
|
533
|
+
darrc_path: Path to the original .darrc file.
|
|
534
|
+
|
|
535
|
+
Raises:
|
|
536
|
+
RuntimeError if something went wrong
|
|
537
|
+
|
|
538
|
+
Returns:
|
|
539
|
+
Path to the filtered .darrc file.
|
|
524
540
|
"""
|
|
525
541
|
# Define options to filter out
|
|
526
542
|
options_to_remove = {"-vt", "-vs", "-vd", "-vf", "-va"}
|
|
@@ -631,8 +647,8 @@ def requirements(type: str, config_setting: ConfigSettings):
|
|
|
631
647
|
script = config_setting.config[type][key]
|
|
632
648
|
try:
|
|
633
649
|
result = subprocess.run(script, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True, check=True)
|
|
634
|
-
logger.
|
|
635
|
-
logger.
|
|
650
|
+
logger.debug(f"{type} {key}: '{script}' run, return code: {result.returncode}")
|
|
651
|
+
logger.debug(f"{type} stdout:\n{result.stdout}")
|
|
636
652
|
if result.returncode != 0:
|
|
637
653
|
logger.error(f"{type} stderr:\n{result.stderr}")
|
|
638
654
|
raise RuntimeError(f"{type} {key}: '{script}' failed, return code: {result.returncode}")
|
|
@@ -711,9 +727,9 @@ def main():
|
|
|
711
727
|
exit(127)
|
|
712
728
|
|
|
713
729
|
if args.suppress_dar_msg:
|
|
714
|
-
logger.info("Suppressing dar messages: -vt, -vs, -vd, -vf
|
|
730
|
+
logger.info("Suppressing dar messages, do not use options: -vt, -vs, -vd, -vf, -va")
|
|
715
731
|
args.darrc = filter_darrc_file(args.darrc)
|
|
716
|
-
logger.debug(f"Filtered .darrc file
|
|
732
|
+
logger.debug(f"Filtered .darrc file: {args.darrc}")
|
|
717
733
|
|
|
718
734
|
start_time=int(time())
|
|
719
735
|
logger.info(f"=====================================")
|
|
@@ -781,12 +797,13 @@ def main():
|
|
|
781
797
|
end_time=int(time())
|
|
782
798
|
logger.info(f"END TIME: {end_time}")
|
|
783
799
|
# Clean up
|
|
784
|
-
if
|
|
785
|
-
if args.darrc.startswith("filtered_darrc_"):
|
|
786
|
-
os.remove(args.darrc)
|
|
787
|
-
|
|
800
|
+
if os.path.exists(args.darrc) and (os.path.dirname(args.darrc) == os.path.expanduser("~")):
|
|
801
|
+
if os.path.basename(args.darrc).startswith("filtered_darrc_"):
|
|
802
|
+
if os.remove(args.darrc):
|
|
803
|
+
logger.debug(f"Removed filtered .darrc: {args.darrc}")
|
|
788
804
|
|
|
789
805
|
|
|
806
|
+
# Determine exit code
|
|
790
807
|
error = False
|
|
791
808
|
logger.debug(f"results[]: {results}")
|
|
792
809
|
if results:
|
|
@@ -795,7 +812,7 @@ def main():
|
|
|
795
812
|
if isinstance(result, tuple) and len(result) == 2:
|
|
796
813
|
msg, exit_code = result
|
|
797
814
|
logger.debug(f"exit code: {exit_code}, msg: {msg}")
|
|
798
|
-
if exit_code
|
|
815
|
+
if exit_code > 0:
|
|
799
816
|
error = True
|
|
800
817
|
args.verbose and print(msg)
|
|
801
818
|
else:
|
dar_backup/util.py
CHANGED
|
@@ -72,7 +72,7 @@ def setup_logging(log_file: str, command_output_log_file: str, log_level: str =
|
|
|
72
72
|
stdout_handler = logging.StreamHandler(sys.stdout)
|
|
73
73
|
stdout_handler.setFormatter(formatter)
|
|
74
74
|
logger.addHandler(stdout_handler)
|
|
75
|
-
secondary_logger.addHandler(stdout_handler)
|
|
75
|
+
#secondary_logger.addHandler(stdout_handler)
|
|
76
76
|
|
|
77
77
|
return logger
|
|
78
78
|
except Exception as e:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dar-backup
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.16
|
|
4
4
|
Summary: A script to do full, differential and incremental backups using dar. Some files are restored from the backups during verification, after which par2 redundancy files are created. The script also has a cleanup feature to remove old backups and par2 files.
|
|
5
5
|
Project-URL: Homepage, https://github.com/per2jensen/dar-backup/tree/main/v2
|
|
6
6
|
Project-URL: Changelog, https://github.com/per2jensen/dar-backup/blob/main/v2/Changelog.md
|
|
@@ -688,8 +688,10 @@ Classifier: Operating System :: POSIX :: Linux
|
|
|
688
688
|
Classifier: Programming Language :: Python :: 3.9
|
|
689
689
|
Classifier: Topic :: System :: Archiving :: Backup
|
|
690
690
|
Requires-Python: >=3.9
|
|
691
|
+
Requires-Dist: inputimeout>=1.0.4
|
|
691
692
|
Description-Content-Type: text/markdown
|
|
692
693
|
|
|
694
|
+
<!-- markdownlint-disable MD024 -->
|
|
693
695
|
# Full, differential or incremental backups using 'dar'
|
|
694
696
|
|
|
695
697
|
The wonderful 'dar' [Disk Archiver](https://github.com/Edrusb/DAR) is used for
|
|
@@ -706,17 +708,20 @@ This is the `Python` based **version 2** of `dar-backup`.
|
|
|
706
708
|
- [Breaking change in version 0.6.0](#breaking-change-in-version-060)
|
|
707
709
|
- [Homepage - Github](#homepage---github)
|
|
708
710
|
- [Requirements](#requirements)
|
|
709
|
-
- [
|
|
711
|
+
- [Principles](#dar-backup-principles)
|
|
710
712
|
- [How to run](#how-to-run)
|
|
711
713
|
- [1 - installation](#1---installation)
|
|
712
714
|
- [2 - configuration](#2---configuration)
|
|
713
715
|
- [3 - generate catalog databases](#3---generate-catalog-databases)
|
|
714
716
|
- [4 - do FULL backups](#4---do-full-backups)
|
|
715
717
|
- [5 - deactivate venv](#5---deactivate-venv)
|
|
716
|
-
- [
|
|
717
|
-
- [
|
|
718
|
-
- [
|
|
719
|
-
- [
|
|
718
|
+
- [Config](#config)
|
|
719
|
+
- [Config file](#config-file)
|
|
720
|
+
- [.darrc](#darrc)
|
|
721
|
+
- [Backup definition](#backup-definition-example)
|
|
722
|
+
- [Systemd examples](#systemctl-examples)
|
|
723
|
+
- [Service: dar-back --incremental-backup](#service-dar-backup---incremental-backup)
|
|
724
|
+
- [Timer: dar-back --incremental-backup](#timer-dar-backup---incremental-backup)
|
|
720
725
|
- [List contents of an archive](#list-contents-of-an-archive)
|
|
721
726
|
- [dar file selection examples](#dar-file-selection-examples)
|
|
722
727
|
- [Select a directory](#select-a-directory)
|
|
@@ -782,9 +787,9 @@ Version 0.6.0 and forwards requires the config variable *COMMAND_TIMEOUT_SECS* i
|
|
|
782
787
|
|
|
783
788
|
## Homepage - Github
|
|
784
789
|
|
|
785
|
-
|
|
790
|
+
'dar-backup' package lives here: [Github - dar-backup](https://github.com/per2jensen/dar-backup/tree/main/v2)
|
|
786
791
|
|
|
787
|
-
This python version is v2 of dar-backup,
|
|
792
|
+
This python version is v2 of dar-backup, v1 is made in bash.
|
|
788
793
|
|
|
789
794
|
## Requirements
|
|
790
795
|
|
|
@@ -798,9 +803,25 @@ On Ubuntu, install the requirements this way:
|
|
|
798
803
|
sudo apt install dar par2 python3
|
|
799
804
|
````
|
|
800
805
|
|
|
801
|
-
##
|
|
806
|
+
## dar-backup principles
|
|
802
807
|
|
|
803
|
-
|
|
808
|
+
### dar-backup
|
|
809
|
+
|
|
810
|
+
`dar-backup` is built in a way that emphasizes getting backups. It loops over the backup definitions, and in the event of a failure while backing up a backup definition, dar-backup shall log an error and start working on the next backup definition.
|
|
811
|
+
|
|
812
|
+
There are 3 levels of backups, FULL, DIFF and INCR.
|
|
813
|
+
|
|
814
|
+
- The author does a FULL yearly backup once a year. This includes all files in all directories as defined in the backup definition(s).
|
|
815
|
+
- The author makes a DIFF once a month. The DIFF backs up new and changed files compared to the FULL backup.
|
|
816
|
+
- The author takes an INCR backup every 3 days. An INCR backup includes new and changed files compared to the DIFF backup.
|
|
817
|
+
-- So, a set of INCR's will contain duplicates (this might change as I become more used to use the catalog databases)
|
|
818
|
+
-- No INCR backups will taken until a DIFF backup has been taken.
|
|
819
|
+
|
|
820
|
+
### cleanup
|
|
821
|
+
|
|
822
|
+
The `cleanup` application deletes DIFF and INCR if the archives are older than the thresholds set up in the configuration file.
|
|
823
|
+
|
|
824
|
+
`cleanup` will only remove FULL archives if the option `--cleanup-specific-archives` is used. It requires the user to confirm deletion of FULL archives.
|
|
804
825
|
|
|
805
826
|
## How to run
|
|
806
827
|
|
|
@@ -814,6 +835,11 @@ Installation is currently in a venv. These commands are installed in the venv:
|
|
|
814
835
|
- clean-log
|
|
815
836
|
- installer
|
|
816
837
|
|
|
838
|
+
Note:
|
|
839
|
+
|
|
840
|
+
The module `inputimeout` is installed into the venv and used for the confirmation input (with a 30 second timeout)
|
|
841
|
+
|
|
842
|
+
|
|
817
843
|
To install, create a venv and run pip:
|
|
818
844
|
|
|
819
845
|
```` bash
|
|
@@ -875,16 +901,18 @@ manager --create-db
|
|
|
875
901
|
|
|
876
902
|
### 4 - do FULL backups
|
|
877
903
|
|
|
878
|
-
|
|
879
|
-
in place in BACKUP.D_DIR (see config file)
|
|
904
|
+
Prereq:
|
|
905
|
+
Backup definitions are in place in BACKUP.D_DIR (see config file)
|
|
906
|
+
|
|
907
|
+
You are ready to do backups of all your backup definitions.
|
|
880
908
|
|
|
881
909
|
```` bash
|
|
882
910
|
dar-backup --full-backup
|
|
883
911
|
````
|
|
884
912
|
|
|
885
|
-
If you want to see dar-backup's log entries in the terminal, use the `--log-stdout` option. This
|
|
913
|
+
If you want to see dar-backup's log entries in the terminal, use the `--log-stdout` option. This can be useful if dar-backup is started by systemd.
|
|
886
914
|
|
|
887
|
-
If you want more log messages, use the `--log-level debug`
|
|
915
|
+
If you want more log messages, use the `--verbose` or `--log-level debug` for even more.
|
|
888
916
|
|
|
889
917
|
If you want a backup of a single definition, use the `-d <backup definition>` option. The definition's name is the filename of the definition in the `backup.d` config directory.
|
|
890
918
|
|
|
@@ -900,7 +928,52 @@ Deactivate the virtual environment (venv)
|
|
|
900
928
|
deactivate
|
|
901
929
|
````
|
|
902
930
|
|
|
903
|
-
##
|
|
931
|
+
## Config
|
|
932
|
+
|
|
933
|
+
### Config file
|
|
934
|
+
|
|
935
|
+
The configuration file's default location is: ~/.config/dar-backup/dar-backup.conf
|
|
936
|
+
|
|
937
|
+
If you have your config file somewhere else, use the `--config` option to point to it.
|
|
938
|
+
|
|
939
|
+
Tilde `~` and environment variables can be used in the paths for various file locations.
|
|
940
|
+
|
|
941
|
+
```` code
|
|
942
|
+
[MISC]
|
|
943
|
+
LOGFILE_LOCATION=~/.dar-backup.log
|
|
944
|
+
MAX_SIZE_VERIFICATION_MB = 20
|
|
945
|
+
MIN_SIZE_VERIFICATION_MB = 1
|
|
946
|
+
NO_FILES_VERIFICATION = 5
|
|
947
|
+
# timeout in seconds for backup, test, restore and par2 operations
|
|
948
|
+
# The author has such `dar` tasks running for 10-15 hours on the yearly backups, so a value of 24 hours is used.
|
|
949
|
+
# If a timeout is not specified when using the util.run_command(), a default timeout of 30 secs is used.
|
|
950
|
+
COMMAND_TIMEOUT_SECS = 86400
|
|
951
|
+
|
|
952
|
+
[DIRECTORIES]
|
|
953
|
+
BACKUP_DIR = /some/where/dar-backup/backups/
|
|
954
|
+
BACKUP.D_DIR = /some/where/dar-backup/backup.d
|
|
955
|
+
TEST_RESTORE_DIR = /tmp/dar-backup/restore/
|
|
956
|
+
|
|
957
|
+
[AGE]
|
|
958
|
+
# age settings are in days
|
|
959
|
+
DIFF_AGE = 100
|
|
960
|
+
INCR_AGE = 40
|
|
961
|
+
|
|
962
|
+
[PAR2]
|
|
963
|
+
ERROR_CORRECTION_PERCENT = 5
|
|
964
|
+
ENABLED = True
|
|
965
|
+
|
|
966
|
+
# scripts to run before the backup to setup the environment
|
|
967
|
+
[PREREQ]
|
|
968
|
+
SCRIPT_1 = ls -l /tmp
|
|
969
|
+
#SCRIPT_2 = another_script.sh
|
|
970
|
+
|
|
971
|
+
[POSTREQ]
|
|
972
|
+
SCRIPT_1 = df -h
|
|
973
|
+
#SCRIPT_2 = another_script.sh
|
|
974
|
+
````
|
|
975
|
+
|
|
976
|
+
### .darrc
|
|
904
977
|
|
|
905
978
|
The package includes a default `.darrc` file which configures `dar`.
|
|
906
979
|
|
|
@@ -1031,6 +1104,48 @@ compress-exclusion:
|
|
|
1031
1104
|
-acase
|
|
1032
1105
|
````
|
|
1033
1106
|
|
|
1107
|
+
### Backup definition example
|
|
1108
|
+
|
|
1109
|
+
This piece of configuration is a `backup definition`. It is placed in the BACKUP.D_DIR (see config file description).
|
|
1110
|
+
The name of the file is the name of the backup definition.
|
|
1111
|
+
|
|
1112
|
+
You can use as many backup definitions as you need.
|
|
1113
|
+
|
|
1114
|
+
```` code
|
|
1115
|
+
# Switch to ordered selection mode, which means that the following
|
|
1116
|
+
# options will be considered top to bottom
|
|
1117
|
+
-am
|
|
1118
|
+
|
|
1119
|
+
# Backup Root Dir
|
|
1120
|
+
# This is the top directory, where the backups start.
|
|
1121
|
+
#Directories mentioned below, are relative to the Root Dir.
|
|
1122
|
+
-R /home/user/
|
|
1123
|
+
|
|
1124
|
+
# Directories to backup below the Root dir
|
|
1125
|
+
# uncomment the next line to backup only the Documents directory
|
|
1126
|
+
# -g Documents
|
|
1127
|
+
|
|
1128
|
+
# Directories to exclude below the Root dir
|
|
1129
|
+
-P mnt
|
|
1130
|
+
-P tmp
|
|
1131
|
+
-P .cache
|
|
1132
|
+
-P .config/Code/CachedData
|
|
1133
|
+
|
|
1134
|
+
# compression level
|
|
1135
|
+
-z5
|
|
1136
|
+
|
|
1137
|
+
# no overwrite, if you rerun a backup, 'dar' halts and asks what to do
|
|
1138
|
+
# due to the -Q option given to `dar`, the program will terminate and give en error.
|
|
1139
|
+
-n
|
|
1140
|
+
|
|
1141
|
+
# size of each slice in the archive
|
|
1142
|
+
--slice 7G
|
|
1143
|
+
|
|
1144
|
+
# bypass directores marked as cache directories
|
|
1145
|
+
# http://dar.linux.free.fr/doc/Features.html
|
|
1146
|
+
--cache-directory-tagging
|
|
1147
|
+
````
|
|
1148
|
+
|
|
1034
1149
|
## Systemctl examples
|
|
1035
1150
|
|
|
1036
1151
|
I have dar-backup scheduled to run via systemd --user settings.
|
|
@@ -1051,7 +1166,7 @@ Verify your timers are set up as you want:
|
|
|
1051
1166
|
systemctl --user list-timers
|
|
1052
1167
|
````
|
|
1053
1168
|
|
|
1054
|
-
## Service: dar-
|
|
1169
|
+
## Service: dar-backup --incremental-backup
|
|
1055
1170
|
|
|
1056
1171
|
File: dar-inc-backup.service
|
|
1057
1172
|
|
|
@@ -1067,7 +1182,7 @@ RemainAfterExit=no
|
|
|
1067
1182
|
ExecStart=/bin/bash -c '. /home/user/programmer/dar-backup.py/venv/bin/activate && dar-backup --incremental-backup --verbose'
|
|
1068
1183
|
````
|
|
1069
1184
|
|
|
1070
|
-
## Timer: dar-
|
|
1185
|
+
## Timer: dar-backup --incremental-backup
|
|
1071
1186
|
|
|
1072
1187
|
File: dar-inc-backup.timer
|
|
1073
1188
|
|
|
@@ -1328,26 +1443,27 @@ done
|
|
|
1328
1443
|
|
|
1329
1444
|
This makes it easier to restore to a given date when having many FULL, DIFF and INCR archives.
|
|
1330
1445
|
|
|
1446
|
+
If the manager does not add an archive to it's catalog database, `dar-backup` will log an error and continue. The important part is verify the archive is usable and continue to other backup definitions.
|
|
1447
|
+
|
|
1331
1448
|
### Performance tip due to par2
|
|
1332
1449
|
|
|
1333
1450
|
This [dar benchmark page](https://dar.sourceforge.io/doc/benchmark.html) has an interesting note on the slice size.
|
|
1334
1451
|
|
|
1335
|
-
Slice size should be smaller than available RAM, apparently a large performance hit can be avoided keeping the
|
|
1452
|
+
Slice size should be smaller than available RAM, apparently a large performance hit can be avoided keeping the par2 data in memory.
|
|
1336
1453
|
|
|
1337
1454
|
### .darrc sets -vd -vf (since v0.6.4)
|
|
1338
1455
|
|
|
1339
1456
|
These .darrc settings make `dar` print the current directory being processed (-vd) and some stats after (-vf)
|
|
1340
|
-
This is very useful in very long running jobs to get an indication that the backup is proceeding normally.
|
|
1341
1457
|
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
The log file can get quite cluttered, if you want the clutter to be removed, run the `clean-log`script.
|
|
1458
|
+
This is very useful in very long running jobs to get an indication that the backup is proceeding normally.
|
|
1345
1459
|
|
|
1346
1460
|
### Separate log file for command output
|
|
1347
1461
|
|
|
1348
1462
|
Dar-backup's log file is called `dar-backup.log`.
|
|
1349
1463
|
|
|
1350
|
-
In order to not clutter that log file with the output of commands being run, a new log file has been introduced `dar-backup-commands.log`.
|
|
1464
|
+
In order to not clutter that log file with the output of commands being run, a new secondary log file has been introduced `dar-backup-commands.log`.
|
|
1465
|
+
|
|
1466
|
+
The secondary log file can get quite cluttered, if you want to remove the clutter, run the `clean-log`script with the `--file` option, or simply delete it.
|
|
1351
1467
|
|
|
1352
1468
|
## Todo
|
|
1353
1469
|
|
|
@@ -1355,7 +1471,7 @@ In order to not clutter that log file with the output of commands being run, a n
|
|
|
1355
1471
|
- FULL, DIFF and INCR backups.
|
|
1356
1472
|
- cleanup.
|
|
1357
1473
|
|
|
1358
|
-
-
|
|
1474
|
+
- Add option to dar-backup to use the `dar` option `--fsa-scope none`
|
|
1359
1475
|
|
|
1360
1476
|
## Reference
|
|
1361
1477
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
dar_backup/.darrc,sha256=-aerqivZmOsW_XBCh9IfbYTUvw0GkzDSr3Vx4GcNB1g,2113
|
|
2
|
-
dar_backup/__about__.py,sha256=
|
|
2
|
+
dar_backup/__about__.py,sha256=iZmWvp4Ehnidf9YJv6Dpn5Sma5S84lPbQtLoYZ2OuiI,22
|
|
3
3
|
dar_backup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
dar_backup/clean_log.py,sha256=cGhtKYnQJ2ceNQfw5XcCln_WNBasbmlfhO3kRydjDNk,5196
|
|
5
|
-
dar_backup/cleanup.py,sha256=
|
|
5
|
+
dar_backup/cleanup.py,sha256=EoT_jTiJmy_HoWxxlWuRn21GoMnr5ioN8yM7qiNRPKE,13351
|
|
6
6
|
dar_backup/config_settings.py,sha256=uicCq6FnpxPFzbv7xfYSXNnQf1tfLk1Z3VIO9M71fsE,4659
|
|
7
7
|
dar_backup/dar-backup.conf,sha256=-wXqP4vj5TS7cCfMJN1nbk-1Sqkq00Tg22ySQXynUF4,902
|
|
8
|
-
dar_backup/dar_backup.py,sha256=
|
|
8
|
+
dar_backup/dar_backup.py,sha256=PI154FIXZiU36iAyLZCCxAciDeBSwoBXYQh0n5JmNEs,37895
|
|
9
9
|
dar_backup/installer.py,sha256=ehp4KSgTc8D9Edsyve5v3NY2MuDbuTFYQQPgou8woV8,4331
|
|
10
10
|
dar_backup/manager.py,sha256=sQl0xdWwBgui11S9Ekg0hOSC4gt89nz_Z8Bt8IPXCDw,21640
|
|
11
|
-
dar_backup/util.py,sha256=
|
|
12
|
-
dar_backup-0.6.
|
|
13
|
-
dar_backup-0.6.
|
|
14
|
-
dar_backup-0.6.
|
|
15
|
-
dar_backup-0.6.
|
|
16
|
-
dar_backup-0.6.
|
|
11
|
+
dar_backup/util.py,sha256=F6U-e-WugxCxLPVoiWsM6_YO8VrDw1wdgGvtnGnig2I,12279
|
|
12
|
+
dar_backup-0.6.16.dist-info/METADATA,sha256=xaYjZK6XAWOc_NHsnktylhdvqWLqzmo94GT1MoR6qLw,76678
|
|
13
|
+
dar_backup-0.6.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
dar_backup-0.6.16.dist-info/entry_points.txt,sha256=Z7P5BUbhtJxo8_nB9qNIMay2eGDbsMKB3Fjwv3GMa4g,202
|
|
15
|
+
dar_backup-0.6.16.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
16
|
+
dar_backup-0.6.16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|