1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#!/usr/bin/env python
from datetime import datetime
import os
import shutil
import re
from glob import glob
from os.path import basename, dirname, exists
root = '/var/lib/rhizi/backup'
debug = True
backup_template = 'backup-%s.dump'
backup_glob = backup_template % '*'
backup_re = re.compile(backup_template % '(\d\d\d\d)(\d\d)(\d\d)')
DAILY_KEPT = 7 # should be >= 7
WEEKLY_KEPT = 5 # should be >= 5
def unlink(filename):
if debug:
print("unlinking %s")
os.unlink(filename)
def makedirs(path):
if exists(path):
return
if debug:
print("makedirs %s" % path)
os.makedirs(path)
def copy(src, dst):
if debug:
print("copy %s %s" % (src, dst))
if not exists(src):
print("bug: %s doesn't exist") % src
raise SystemExit
dst_path = dirname(dst)
if not exists(dst_path):
makedirs(dst_path)
shutil.copy(src, dst)
def neo4jshell(command, stdout):
cmdline = "neo4j-shell -c '%s' > '%s'" % (command, stdout)
if debug:
print("executing %r" % cmdline)
os.system(cmdline)
def next_daily_filename():
filename = os.path.join(daily_root(), backup_template % datetime.now().strftime('%Y%m%d'))
return filename
def daily_root():
return os.path.join(root, 'daily')
def weekly_root():
return os.path.join(root, 'weekly')
def monthly_root():
return os.path.join(root, 'monthly')
def backup_year_month_day(filename):
return map(int, backup_re.match(basename(filename)).groups())
def to_weekly(filename):
year, month, day = backup_year_month_day(filename)
_, (wkly_year, wkly_month, wkly_day) = latest_weekly()
#import pdb; pdb.set_trace()
delta = datetime(year, month, day) - datetime(wkly_year, wkly_month, wkly_day)
return delta.days >= 7
def to_monthly(filename):
""" return True if filename is newer by a month from the newest monthly """
year, month, day = backup_year_month_day(filename)
_, (monthly_year, monthly_month, monthly_day) = latest_monthly()
if monthly_year < year:
month += 12
return month > monthly_month and day >= monthly_day
def latest_weekly():
return latest(weekly_root())
def latest_monthly():
return latest(monthly_root())
def latest(subdir):
"""
returns filename, (year, month, day)
"""
filenames = glob(os.path.join(subdir, backup_glob))
if len(filenames) == 0:
return 'no_such_file', (1848, 1, 1)
return max((fname, backup_year_month_day(fname)) for fname in filenames)
def sorted_backups(subdir):
def cmp_files(fa, fb):
ta = os.stat(fa).mtime
tb = os.stat(fb).mtime
if ta == tb:
return 0
if ta < tb:
return -1
return 1
return sorted(glob(os.path.join(weekly_root(), backup_glob)), cmp=cmp_files)
def create_daily_backup():
filename = next_daily_filename()
makedirs(dirname(filename))
neo4jshell("dump", stdout=filename)
return filename
def main():
# create the daily backup
filename = create_daily_backup()
# copy out to weekly if a week passed since last weekly, otherwise remove excess
if to_weekly(filename):
copy(filename, os.path.join(weekly_root(), basename(filename)))
for filename in sorted_backups(daily_root())[DAILY_KEPT:]:
unlink(filename)
# rotate out to monthly if a month passed since last monthly, otherwise remove excess
if to_monthly(filename):
copy(filename, os.path.join(monthly_root(), basename(filename)))
for filename in sorted_backups(weekly_root())[WEEKLY_KEPT:]:
unlink(filename)
if __name__ == '__main__':
main()
|