draft disaster recovery mode for deltatar
[python-delta-tar] / backup.py
1 #!/usr/bin/env python3
2
3 # Copyright (C) 2013 Intra2net AG
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as published
7 # by the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see
17 # <http://www.gnu.org/licenses/lgpl-3.0.html>
18
19 import argparse
20 import binascii
21 import json
22 import logging
23 import os
24 import re
25 import random
26 import shutil
27 from datetime import datetime
28 from functools import partial
29
30 from deltatar.deltatar import DeltaTar, NO_MATCH, MATCH, PARENT_MATCH
31 from deltatar.tarfile import TarFile, GNU_FORMAT
32
33 consoleLogger = logging.StreamHandler()
34 consoleLogger.setLevel(logging.DEBUG)
35
36 def check_equal_dirs(path1, path2, deltatar):
37     '''
38     compare the two directories source_dir and target_dir and check
39     # they are the same
40     '''
41     nbars1 = len(path1.split('/'))
42     nbars2 = len(path2.split('/'))
43
44     source_it = deltatar._recursive_walk_dir(path1)
45     source_it = deltatar.jsonize_path_iterator(source_it, strip=nbars1)
46     target_it = deltatar._recursive_walk_dir(path2)
47     target_it = deltatar.jsonize_path_iterator(target_it, strip=nbars2)
48     while True:
49         try:
50             sitem = next(source_it)
51             titem = next(target_it)
52         except StopIteration:
53             try:
54                 titem = next(target_it)
55                 raise Exception("iterators do not stop at the same time")
56             except StopIteration:
57                 break
58         try:
59             assert deltatar._equal_stat_dicts(sitem, titem)
60         except Exception as e:
61             print(sitem)
62             print(titem)
63             print("FAIL")
64             raise
65
66 if __name__ == "__main__":
67     #import tracemalloc
68     #tracemalloc.enable()
69     #top = tracemalloc.DisplayTop(25)
70     #top.show_lineno = True
71     #top.start(20)
72     parser = argparse.ArgumentParser()
73
74     parser.add_argument("-m", "--mode", default='',
75                         help=
76                             """Mode in which to read/write the backup.
77                             Valid modes are:
78                                        ''           open uncompressed;
79                                        'gz'         open with gzip compression;
80                                        'bz2'        open with bzip2 compression;
81                                        '#gz'        encrypted stream of individually
82                                                     compressed tar blocks.
83                             To enable encryption, supply a password.
84                             """)
85     parser.add_argument("-t", "--targetpath", help="Target path directory.")
86     parser.add_argument("-s", "--sourcepath", help="Source path directory.")
87     epw = os.getenv ("PDTCRYPT_PASSWORD")
88     parser.add_argument("-p", "--password",
89                         default=epw.strip () if epw is not None else None,
90                         help="Password for symmetric encryption. "
91                              "The environment variable PDTCRYPT_PASSWORD should "
92                              "be preferred to this. Enables encryption.")
93     parser.add_argument("-v", "--volsize", default=None,
94                         help="Maximum volume size, in megabytes.")
95     parser.add_argument("-r", "--restore", action='store_true',
96                         help="Restore a backup.")
97     parser.add_argument("-R", "--recover", action='store_true',
98                         help="Restore a backup with an index file.")
99     parser.add_argument("-f", "--full", action='store_true',
100                         help="Create a full backup.")
101     parser.add_argument("-d", "--diff", action='store_true',
102                         help="Create a diff backup.")
103     parser.add_argument("-i", "--indexes", nargs='+', help="Indexes paths.")
104     parser.add_argument("-l", "--list-files", action='store_true',
105                         help="List files in a tarball.")
106     parser.add_argument("-x", "--excluded", nargs='+', default=[],
107                         help="Files to exclude from backup.")
108     parser.add_argument("-inc", "--included", nargs='+', default=[],
109                         help="Files to include in the backup.")
110     parser.add_argument("-ip", "--included-path", default=None,
111                         help="Path to a file containing a list of included paths.")
112     parser.add_argument("-xp", "--excluded-path", default=None,
113                         help="Path to a file containing a list of excluded paths.")
114     parser.add_argument("-e", "--equals", action='store_true',
115                         help="Check if two dirs are equal.")
116
117     args = parser.parse_args()
118
119     if args.excluded_path:
120         f = open(args.excluded_path, 'r')
121         excluded_files = f.readlines()
122         f.close()
123     else:
124         excluded_files = args.excluded
125
126     if args.included_path:
127         f = open(args.included_path, 'r')
128         included_files = f.readlines()
129         f.close()
130     else:
131         included_files = args.included
132
133     deltatar = DeltaTar(mode=args.mode, password=args.password,
134         logger=consoleLogger, excluded_files=excluded_files,
135         included_files=included_files)
136
137     if args.full:
138         deltatar.create_full_backup(args.sourcepath, args.targetpath, args.volsize)
139     elif args.diff:
140         deltatar.create_diff_backup(args.sourcepath, args.targetpath, args.indexes[0], args.volsize)
141     elif args.list_files:
142         deltatar.list_backup(args.sourcepath, lambda e: print (e.name))
143     elif args.restore:
144         if args.indexes is not None:
145             deltatar.restore_backup(args.targetpath, backup_indexes_paths=args.indexes)
146         else:
147             deltatar.restore_backup(args.targetpath, backup_tar_path=args.sourcepath)
148     elif args.recover:
149         failed = deltatar.recover_backup(args.targetpath,
150                                          backup_indexes_paths=args.indexes,
151                                          backup_tar_path=args.sourcepath)
152         if len (failed) > 0:
153             logger = logging.getLogger('deltatar.DeltaTar')
154             print ("%d files could not be restored:" % len (failed))
155             for i, f in enumerate (failed):
156                 print ("   [%d] %s (%s)" % (i, f [0], f [1]))
157
158     elif args.equals:
159         check_equal_dirs(os.path.abspath(args.sourcepath), os.path.abspath(args.targetpath), deltatar)
160     else:
161         import sys
162         print("Nothing to do.\nPlease specify one of --full, --diff, --list-files, "
163               "--restore, --equals.\n", file=sys.stderr)
164         parser.print_help(file=sys.stderr)
165
166