I've written this Python script to make regular backups of a Linux server. It works pretty well except that the script sometimes backups files more than one time, which is pretty strange and I don't know why that happens.
But that's not the key point of my posting here (just someone may see a little error I've made which explains this behaviour). Since I've learned all I know about Python by myself I'm a little bit nervous to use my own code in a productive environment, so I need a code review.
In short the script should check all files in the filesystem of a Linux server except a small collection of directories to avoid. Every 'walked' file should be checked for last modification date. If it's been modified within the last 24 hours it should backup and log into its logfile. Further more it should check after each run how many backups exist on the network share and if a certain number is reached it should delete the oldest one.
import datetime
import re
import os
import subprocess
import socket
import glob
from stat import *
import time
from collections import defaultdict
host = socket.gethostname()
date = datetime.datetime.today()
date = date.strftime("%Y-%m-%d")
mountPoint = "/mnt/linuxbackup/"
nas = '//172.19.3.5/backup/linuxserver'
credentials = 'sec=ntlm,credentials=/root/.backup.secret'
dirPath = '/'
past = time.time() - 86400
# Global settings
fullBackup_dict = {
'backupdir' : mountPoint + host + '/',
'backupname' : host + '.' + date,
'backupstokeep' : 4,
'excludelist' : ('/proc',
'/lost+found',
'/sys',
'/media',
'/var/cache',
'/var/log',
'/mnt',
'/dev',
'/run',
'/tmp'
),
}
dailyBackupDict = defaultdict(list)
includelist = ''
excludelist = ''
for a in fullBackup_dict['excludelist']:
excludelist = excludelist + '--exclude=%s ' %a
fullBackup_dict['excludelist'] = excludelist
if os.path.exists(mountPoint):
if not os.path.ismount(mountPoint):
subprocess.check_call(["mount", "-t", "cifs", "-o", credentials, nas, mountPoint])
if not os.path.exists(fullBackup_dict['backupdir']):
os.makedirs(fullBackup_dict['backupdir'])
else:
os.makedirs(mountPoint)
subprocess.check_call(["mount", "-t", "cifs", "-o", credentials, nas, mountPoint])
class backup:
def __init__(self, backupdir, backupname):
self.backupdir = backupdir
self.backupname = backupname
self.run()
def run(self,):
# Getting a list of previous backups
fnames = [os.path.basename(x) for x in
glob.glob(self.backupdir + host + '.[0-9][0-9][0-9][0-9]' +
'-[0-9][0-9]' + '-[0-9][0-9]' + '.tar.bz2')]
#print self.backupdir + host + '[0-9][0-9][0-9][0-9]' + '-[0-9][0-9]' + '-[0-9][0-9]' + '.tar.bz2'
print 'fnames = %s' %fnames
print 'Backing up the system'
# Full Backup
if datetime.date.today().strftime("%A") == "Friday":
command = 'nice -n 10 tar cvpjf ' + self.backupdir + self.backupname + '_FULL' + '.tar.bz2 ' \
+ fullBackup_dict['excludelist'] + ' / ' + '--index-file ' + self.backupdir + self.backupname + '.log' + ' 2>&1'
# daily Backup
else:
includelist = ''
try:
for path, dirs, files in os.walk(dirPath, topdown=True):
files = [f for f in files if not f[0] == '.']
dirs[:] = [d for d in dirs if (d not in fullBackup_dict['excludelist']) and (d[0] != '.')]
for fn in files:
filePath = os.path.join(path, fn)
try:
if os.path.getmtime(filePath) >= past:
if os.path.islink(filePath):
continue
else:
dailyBackupDict['includelist'].append(filePath)
for addFiles in dailyBackupDict['includelist']:
includelist = includelist + '--add-file="%s" ' %addFiles
except OSError:
pass
except OSError:
pass
dailyBackupDict['includelist'] = includelist
command = 'nice -n 10 tar cvpjf ' + self.backupdir + self.backupname + '.tar.bz2 ' + fullBackup_dict['excludelist'] \
+ dailyBackupDict['includelist'] + ' > ' + self.backupdir + self.backupname + '.log' + ' 2>&1'
print command
os.system(command)
while len(fnames) > fullBackup_dict['backupstokeep']:
print 'more than %s file(s) here!' %fullBackup_dict['backupstokeep']
print 'Removing oldest file'
filetimes = {}
accesstimes = []
for filename in fnames:
print self.backupdir + filename
mode = os.stat(self.backupdir + filename)[ST_MTIME]
filetimes[mode] = filename
accesstimes.append(mode)
print mode
accesstimes.sort()
print filetimes
print accesstimes
fileToDelete = filetimes[accesstimes[0]]
print 'Deleting file %s' %fileToDelete
try:
os.remove(self.backupdir + fileToDelete)
os.remove(self.backupdir + fileToDelete[:-7] + 'log')
except Exception, inst:
print inst
fnames = [os.path.basename(x) for x in
glob.glob(self.backupdir + host + '-' + '[0-9][0-9][0-9][0-9]' + '-' + '[0-9][0-9]' +
'-' + '[0-9][0-9]' + '.tar.bz2')]
print '%s%s' %(self.backupdir,self.backupname)
if os.path.ismount(mountPoint):
subprocess.check_call(["umount", mountPoint])
def main():
backup(fullBackup_dict['backupdir'], fullBackup_dict['backupname'])
if __name__ == '__main__':
main()