Skip to content

Commit 2a96b34

Browse files
committed
Refactor rotate backups script out.
One, we can now reuse the rotate module in both mysql backups and filesystem backups. Two it will make it easier to do a push based backup script.
1 parent c92e83e commit 2a96b34

File tree

5 files changed

+224
-100
lines changed

5 files changed

+224
-100
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.pyc

__init__.py

Whitespace-only changes.

incrbackup renamed to incrbackup.py

Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import datetime
1414
import subprocess
1515
import json
16+
import rotatebackups
1617

1718
from operator import itemgetter
1819

@@ -64,58 +65,18 @@ def run_command(self, command=None, shell=False, ignore_errors=False,
6465

6566
def backup(self):
6667

68+
padding = len(str(self.keep))
6769
backups = []
68-
69-
# add the backup directories to a list, dirs are the form num.prefix.date
70-
for backup_dir in os.listdir(self.store):
71-
bparts = backup_dir.split(".")
72-
if len(bparts) == 3 and bparts[0].isdigit():
73-
bparts.append(backup_dir)
74-
backups.append(bparts)
7570

7671
# get the current date and timestamp and the zero backup name
7772
now = datetime.datetime.now()
7873
tstamp = now.strftime("%Y%m%d%H%M%S")
79-
zbackup_name = string.join(["0000", self.name, tstamp], ".")
74+
zbackup_name = string.join(["".zfill(padding), tstamp, self.name], ".")
8075
zbackup_path = self.store + os.sep + zbackup_name
81-
82-
# only need to process backup directories if we have some
83-
if len(backups) > 0:
84-
85-
# order the backups in the list by reverse number, highest first
86-
backups = sorted(backups, key=itemgetter(0), reverse=True)
87-
logging.debug(backups)
8876

89-
# perform shifting and processing on the backup directories
90-
for bparts in backups:
91-
92-
# remove backups >= number of days to keep
93-
bnum = int(bparts[0])
94-
if bnum >= self.keep:
95-
bpath = self.store + os.sep + bparts[3]
96-
logging.debug(["rm", "-fr", bpath])
97-
self.run_command(["rm", "-fr", bpath])
98-
else:
99-
100-
# above 0 gets shifted to one number higher and moved, 0 gets hardlink
101-
# copied to 1
102-
old_bpath = self.store + os.sep + bparts[3]
103-
num_prefix = str(bnum + 1).zfill(4)
104-
new_backup_name = string.join([num_prefix, bparts[1], bparts[2]], ".")
105-
new_bpath = self.store + os.sep + new_backup_name
106-
if bnum > 0:
107-
logging.debug([bnum, "mv", old_bpath, new_bpath])
108-
self.run_command(["mv", old_bpath, new_bpath])
109-
elif bnum == 0:
110-
logging.debug(["cp", "-al", old_bpath, new_bpath])
111-
self.run_command(["cp", "-al", old_bpath, new_bpath])
112-
113-
# change the name of the 0 directory if it exists
114-
zbackup = backups[-1]
115-
if zbackup:
116-
old_bpath = self.store + os.sep + zbackup[3]
117-
logging.debug([0, "mv", old_bpath, zbackup_path])
118-
self.run_command(["mv", old_bpath, zbackup_path])
77+
# rotate the backups
78+
rotater = rotatebackups.RotateBackups(self.keep, self.store)
79+
rotater.rotate_backups()
11980

12081
# create the base rsync command with excludes
12182
rsync_base = ["rsync", "-avR", "--ignore-errors", "--delete", "--delete-excluded"]
@@ -239,8 +200,7 @@ def main(argv):
239200
finally:
240201
os.remove(pid_file)
241202

242-
# if we are running the script from the command line, run the main
243-
# method of the JobStream class
203+
# if we are running the script from the command line, run the main function
244204
if __name__ == "__main__":
245205
main(sys.argv[1:])
246206

mysqlbackup renamed to mysqlbackup.py

Lines changed: 24 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import tempfile
1313
import datetime
1414
import subprocess
15+
import rotatebackups
1516

1617
from operator import itemgetter
1718

@@ -33,12 +34,12 @@
3334
"""
3435
class MysqlBackup:
3536

36-
def __init__(self, keep=90, databases=None, backup_root=None, user="root",
37+
def __init__(self, keep=90, databases=None, store=None, user="root",
3738
password=None, host=None):
3839
self.host = host
3940
self.keep = keep
4041
self.databases = databases
41-
self.backup_root = backup_root
42+
self.store = store
4243
self.user = user
4344
self.password = password
4445
self.host = host
@@ -65,63 +66,33 @@ def get_databases(self):
6566

6667
def backup(self):
6768

69+
padding = len(str(self.keep))
6870
backups = []
69-
70-
# add the backup directories to a list, dirs are the form num.prefix.date
71-
for backup_dump in os.listdir(self.backup_root):
72-
bparts = backup_dump.split(".")
73-
if len(bparts) == 5 and bparts[0].isdigit():
74-
bparts.append(backup_dump)
75-
backups.append(bparts)
76-
71+
72+
# rotate the backups
73+
rotater = rotatebackups.RotateBackups(self.keep, self.store)
74+
rotater.rotate_backups()
75+
7776
# get the current date and timestamp and the zero backup name
7877
now = datetime.datetime.now()
7978
tstamp = now.strftime("%Y%m%d%H%M%S")
8079

81-
# only need to process backup directories if we have some
82-
if len(backups) > 0:
83-
84-
# order the backups in the list by reverse number, highest first
85-
backups = sorted(backups, key=itemgetter(0), reverse=True)
86-
logging.debug(backups)
87-
88-
# perform shifting and processing on the backup directories
89-
for bparts in backups:
90-
91-
# remove backups >= number to keep
92-
bnum = int(bparts[0])
93-
if bnum >= self.keep:
94-
bpath = self.backup_root + os.sep + bparts[-1]
95-
logging.debug(["rm", "-f", bpath])
96-
self.run_command(["rm", "-f", bpath])
97-
else:
98-
99-
# above 0 gets shifted to one number higher and moved, 0 gets hardlink
100-
# copied to 1
101-
old_bpath = self.backup_root + os.sep + bparts[-1]
102-
num_prefix = str(bnum + 1).zfill(4)
103-
new_backup_name = string.join([num_prefix] + bparts[1:5], ".")
104-
new_bpath = self.backup_root + os.sep + new_backup_name
105-
if bnum >= 0:
106-
logging.debug([bnum, "mv", old_bpath, new_bpath])
107-
self.run_command(["mv", old_bpath, new_bpath])
108-
10980
databases = self.get_databases()
11081
skip = ["information_schema", "performance_schema", "test"]
111-
for database in databases:
112-
if database in skip:
82+
for db in databases:
83+
if db in skip:
11384
continue
11485

115-
dbbackup_name = string.join(["0000", database, tstamp, "sql"], ".")
116-
dbbackup_path = self.backup_root + os.sep + dbbackup_name
86+
dbbackup_name = string.join(["".zfill(padding), tstamp, db, "sql"], ".")
87+
dbbackup_path = self.store + os.sep + dbbackup_name
11788

11889
dump_cmd = "mysqldump -u " + self.user
11990
if self.host != None:
12091
dump_cmd += " -h " + "'" + self.host + "'"
12192
if self.password != None:
12293
dump_cmd += " -p" + self.password
123-
dump_cmd += " -e --opt -c " + database + " | gzip > " + dbbackup_path + ".gz"
124-
logging.info("Dump db, %s to %s." % (database, dbbackup_path))
94+
dump_cmd += " -e --opt -c " + db + " | gzip > " + dbbackup_path + ".gz"
95+
logging.info("Dump db, %s to %s." % (db, dbbackup_path))
12596
os.popen(dump_cmd)
12697

12798
"""
@@ -151,13 +122,13 @@ def main(argv):
151122
user = None
152123
password = None
153124
host = None
154-
backup_root = None
125+
store = None
155126

156127
try:
157128

158129
# process the command line options
159-
opts, args = getopt.getopt(argv, "hn:k:d:b:u:p:s:", ["help", "keep=",
160-
"databases=", "backup-root=", "user=", "password=", "host="])
130+
opts, args = getopt.getopt(argv, "hn:k:d:t:u:p:s:", ["help", "keep=",
131+
"databases=", "store=", "user=", "password=", "host="])
161132

162133
# if no arguments print usage
163134
if len(argv) == 0:
@@ -174,8 +145,8 @@ def main(argv):
174145
keep = int(arg)
175146
elif opt in ("-d", "--databases"):
176147
server = arg
177-
elif opt in ("-b", "--backup-root"):
178-
backup_root = arg
148+
elif opt in ("-t", "--store"):
149+
store = arg
179150
elif opt in ("-u", "--user"):
180151
user = arg
181152
elif opt in ("-p", "--password"):
@@ -190,8 +161,8 @@ def main(argv):
190161
sys.exit(errno.EIO)
191162

192163
# check options are set correctly
193-
if user == None or backup_root == None:
194-
logging.warning("Backup root (-b) is required")
164+
if user == None or store == None:
165+
logging.warning("Backup store directory (-t) and user (-u) are required")
195166
usage()
196167
sys.exit(errno.EPERM)
197168

@@ -210,14 +181,14 @@ def main(argv):
210181
f.close()
211182

212183
# create the backup object and call its backup method
213-
mysql_backup = MysqlBackup(keep, databases, backup_root, user, password, host)
184+
mysql_backup = MysqlBackup(keep, databases, store, user, password, host)
214185
mysql_backup.backup()
215186

216187
except(Exception):
217188
logging.exception("Mysql backups failed.")
218189
finally:
219190
os.remove(pid_file)
220191

221-
# if we are running the script from the command line
192+
# if we are running the script from the command line, run the main function
222193
if __name__ == "__main__":
223194
main(sys.argv[1:])

0 commit comments

Comments
 (0)