/
backup.py
executable file
·272 lines (202 loc) · 8.16 KB
/
backup.py
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys, syslog, shutil
import time, string
import tarfile , ftplib, ConfigParser
from optparse import OptionParser, OptionGroup
#========================================================
# Global Vars
#========================================================
VERSION = "1.0"
VERSION_DATE = "May 15 2013 16:15:08"
TIME_BEGIN = time.clock()
DATE = time.strftime("%Y%m%d_%Hh%M")
#========================================================
# Functions
#========================================================
def parseArgs():
"""Parse any command line options."""
parser = OptionParser()
group = OptionGroup(parser, "Basics Options")
group.add_option("-c", "--conffile", dest="conffile", help="Config file")
group.add_option("-p", "--period", dest="period", help="Period : hourly / daily / weekly / monthly / yearly", default='daily')
group.add_option("-t", "--tmpdir", dest="tmp", help="Temporary working directory (by default /tmp)", default="/tmp")
parser.add_option_group(group)
group = OptionGroup(parser, "Program Options")
group.add_option("--template", dest="template", help="Create config file example", default="False")
group.add_option("-d", "--debug", dest="debug", action="store_true", help="Print debug information", default="False")
group.add_option("-v", "--version", dest="version", action="store_true", help="Print version information and exit", default="False")
parser.add_option_group(group)
(options, args) = parser.parse_args()
# Print version information
if options.version == True:
print "Backup v%s (modified %s)" %(VERSION, VERSION_DATE)
print "Created by Steven Ducastelle"
sys.exit(0)
# Create template config file
if options.template != "False":
createTemplate(options)
# Print error and help if no argument is passed
if ((options.conffile is None) and (options.template == "False")):
sys.stderr.write("Missing argument(s).\n")
sys.stderr.write(parser.parse_args(["--help"]))
return (options, args)
def createTemplate(options):
"""Create template config file in specific dir"""
tmpFile = options.template
content="""[backup]
; Name of backup
name=backup1
syslog=True
; List files to backup separate with coma
files: /etc/fstab,/root/.bashrc
; List directories to backup separate with coma
dirs= /var/www,/var/lib
; backup Mysql
mysqldb= db1,db2
userdb=adminsql
passdb=password!
# Dir / Mount / NFS
[export-fs]
enable=False
dest=/tmp
; Separate multi destination with coma
# By SCP
; Use authentication with certificate
[export-scp]
enable=False
host=
user=
dest=
# By RSYNC with ssh
[export-rsync]
enable=False
host=
user=
pass=
dest=
# By FTP
[export-ftp]
enable=False
host=
user=
pass=
dest=
"""
tmpFile = open(tmpFile, 'w')
tmpFile.write(content)
tmpFile.close()
sys.exit(0)
return True
def splitComa(data):
"""Split string"""
return string.split(str(data), ',')
def logger(data):
"""Write in syslog and debug if asked by user"""
if str(config.get('backup', 'syslog')).lower() == 'true':
syslog.syslog(syslog.LOG_INFO, 'backup.py ' + data)
if options.debug is True:
print '>>> DEBUG (',time.clock(),') :',data
return True
def formatPath(data):
"""Format path in same syntax"""
# Supress the / at the end
if data[-1] == '/':
data = data[:-1]
return data
def humanSizeof(num):
for x in ['bytes','KB','MB','GB']:
if num < 1024.0 and num > -1024.0:
return "%3.1f%s" % (num, x)
num /= 1024.0
return "%3.1f%s" % (num, 'TB')
#========================================================
# Main
#========================================================
# Get the command line options and arguments:
(options, args) = parseArgs()
# Vars
tmpPath = formatPath(options.tmp) + '/backup-' + DATE + '_' + options.period
tarName = 'backup-' + DATE + '_' + options.period + '.tar.gz'
tarPath = tmpPath + '/' + tarName
config = ConfigParser.RawConfigParser() # Open config file
config.read(options.conffile) # read config file
logger("Backup start (" + str(config.get('backup', 'name')) + ') - Type : ' + str(options.period));
# Creating temporary dir
if not os.path.exists(tmpPath):
try:
os.makedirs(tmpPath)
except OSError, e:
logger('Error when creating temporary directory : ' + str(e))
sys.exit(1)
# Creating archive
tar = tarfile.open(tarPath, "w:gz")
logger('Creating archive (' + tarName + ') ...')
################################
# Backup files and directories #
################################
for f in splitComa(config.get('backup', 'files')): # Add each file
tar.add(f.strip())
for d in splitComa(config.get('backup', 'dirs')): # Add each dirs
tar.add(d.strip())
##############
# Dump Mysql #
##############
if config.get('backup', 'mysqldb') != '':
logger('MySQL dump bases...')
bases = splitComa(config.get('backup', 'mysqldb')) # Fetches the list of databases
for db in bases:
db = db.strip() # Removes spaces at the beginning and end of the character string
fdb = "dump-Mysql_" + db + "_" + DATE + ".sql" # Name of dump sql file
logger('Dump base ' + db)
os.system("mysqldump --add-drop-table -c -u " + config.get('backup', 'userdb') + " -p" + config.get('backup', 'passdb') + " " + db + " > " + tmpPath + "/" + fdb) # Dump
tar.add(tmpPath + "/" + fdb, arcname=fdb) # Add file in archive backup
logger('MySQL dump completed')
tar.close() # Close archive
arcSize = humanSizeof(os.path.getsize(tarPath)) # Size of archive
logger('Archive completed')
###########
# Exports #
###########
# Export in filesytem or mount point
if str(config.get('export-fs', 'enable')).lower() == 'true':
for fs in splitComa(config.get('export-fs', 'dest')): # Fetches the list of destination
fs = formatPath(fs) # Clean path
logger('Export to directory (' + fs + '/' + config.get('backup', 'name') + '/' + str(options.period) + ') ...')
try:
if not os.path.exists(fs + '/' + config.get('backup', 'name') + '/' + str(options.period)): # Create directory if not exist
os.makedirs(fs + '/' + config.get('backup', 'name') + '/' + str(options.period))
try:
shutil.copyfile(tarPath, fs + '/' + config.get('backup', 'name') + '/' + str(options.period) + '/' + tarName ) # Copy file in directory
except IOError, e:
logger('Error during file export : ' + str(e))
except OSError, e:
logger('Error when creating temporary directory : ' + str(e))
logger('Directory export completed')
## Export SCP
if str(config.get('export-scp', 'enable')).lower() == 'true':
logger('Export to SCP (' + str(config.get('export-scp', 'host')) + ')...')
os.system("scp " + tarPath + " " + str(config.get('export-scp', 'user')).strip() + "@" + str(config.get('export-scp', 'host')).strip() + ":" + formatPath(config.get('export-scp', 'dest')) + " > /dev/null") # Copy tar.gz with scp
logger('SCP export completed')
## Export RSYNC
if str(config.get('export-rsync', 'enable')).lower() == 'true':
logger('Export to RSYNC (' + str(config.get('export-rsync', 'host')) + ')...')
os.system("rsync -e ssh -az " + tarPath + " " + str(config.get('export-rsync', 'user')).strip() + "@" + str(config.get('export-rsync', 'host')).strip() + ":" + formatPath(config.get('export-rsync', 'dest')) + " > /dev/null") # Copy tar.gz with rsync
logger('RSYNC export completed')
## Export FTP
if str(config.get('export-ftp', 'enable')).lower() == 'true':
logger('Export to FTP (' + str(config.get('export-ftp', 'host')) + ')...')
try:
ftp = ftplib.FTP(config.get('export-ftp','host'), config.get('export-ftp','user'), config.get('export-ftp','pass')) # Ftp connection
ftp.cwd(str(config.get('export-ftp', 'dest')).strip()) # Go to the destination directory
ftp.storbinary(('STOR ' + config.get('export-ftp', 'dest') + '/' + tarName).encode('utf-8'), open(tarPath, 'rb')) # Upload tar.gz
except Exception, e:
logger('Error to FTP export : ' + str(e))
logger('FTP export completed')
# Deleting temporary files
try:
shutil.rmtree(tmpPath)
except OSError, e:
logger('Error when deleting temporary directory : ' + str(e))
timeExecution = time.clock() - TIME_BEGIN # Calculate time execution
logger('Backup completed, size:' + str(arcSize) + ' (time execution:' + str(timeExecution) + 's)')