1 # Cumulus: Efficient Filesystem Backup to the Cloud
2 # Copyright (C) 2012 The Cumulus Developers
3 # See the AUTHORS file for a list of contributors.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
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 General Public License for more details.
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 """The Python-based Cumulus script.
21 This implements maintenance functions and is a wrapper around the C++
22 cumulus-backup program.
30 from cumulus import cmd_util
31 from cumulus import config
36 def prune_backups(backup_config, scheme):
37 store = cumulus.LowlevelDataStore(backup_config.get_global("dest"))
38 snapshot_re = re.compile(r"^(.*)-(.*)$")
39 retention = backup_config.get_retention_for_scheme(scheme)
40 expired_snapshots = []
41 for snapshot in sorted(store.list_snapshots()):
42 m = snapshot_re.match(snapshot)
43 if m.group(1) != scheme: continue
44 timestamp = m.group(2)
45 keep = retention.consider_snapshot(timestamp)
47 expired_snapshots.append(snapshot)
48 # The most recent snapshot is never removed.
49 if expired_snapshots: expired_snapshots.pop()
50 print expired_snapshots
52 # TODO: Clean up the expiration part...
53 for snapshot in expired_snapshots:
54 store.store.delete("snapshot", "snapshot-%s.lbs" % snapshot)
56 print "Collecting garbage..."
57 options = FakeOptions()
58 options.store = backup_config.get_global("dest")
59 options.dry_run = False
60 cmd_util.options = options
61 cmd_util.cmd_garbage_collect([])
63 def prune_localdb(backup_config, scheme, next_snapshot=None):
64 """Clean old snapshots out of the local database.
66 Clear old snapshots out of the local database, possibly in preparation for
67 running a new backup. One snapshot of each configured retention period is
68 kept (i.e., one weekly and one daily), and the most recent snapshot is
69 always retained. If next_snapshot is not None, it should be the timestamp
70 when (approximately) the next snapshot will be taken; if that snapshot
71 would be a daily, weekly, etc. snapshot, then it may result in the previous
72 snapshot of the same duration being evicted from the local database.
74 Note that in this sense, "evict" merely refers to tracking the snapshots in
75 the local database; this function does not delete backups from the backup
78 # Fetch the list of existing snapshots in the local database. Pruning only
79 # makes sense if there are more than one snapshots present.
80 db = cumulus.LocalDatabase(backup_config.get_global("localdb"))
81 snapshots = sorted(db.list_snapshots(scheme))
82 if len(snapshots) <= 1:
85 # Classify the snapshots (daily, weekly, etc.) and keep the most recent one
86 # of each category. Also ensure that the most recent snapshot is retained.
87 retention = backup_config.get_retention_for_scheme(scheme)
88 for snapshot in snapshots:
89 retention.consider_snapshot(snapshot)
90 if next_snapshot is not None:
91 retention.consider_snapshot(next_snapshot)
92 retained = set(retention.last_snapshots().values())
93 retained.add(snapshots[-1])
94 print retention.last_snapshots()
97 print s, s in retained
99 evicted = [s for s in snapshots if s not in retained]
101 db.delete_snapshot(scheme, s)
106 backup_config = config.CumulusConfig(argv[1])
107 for scheme in backup_config.backup_schemes():
109 #prune_backups(backup_config, scheme)
110 prune_localdb(backup_config, scheme, datetime.datetime.utcnow())
111 #prune_localdb(backup_config, scheme, datetime.datetime(2013, 1, 1))
113 if __name__ == "__main__":