Advertisement
Guest User

Untitled

a guest
May 24th, 2018
192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.67 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. import os
  4. import subprocess
  5. import sys
  6. import datetime
  7. import shutil
  8. from datetime import datetime, timedelta
  9.  
  10. import glob
  11. import string
  12. import re
  13. import shlex
  14.  
  15. import smtplib
  16. import email
  17.  
  18. #basic config - please do not change
  19. HOSTNAME = os.uname()[1]
  20. LOCKDIR = "/tmp/somedir" #LOCKDIR
  21. LOGFILE = "/var/log/somelogfile" #LOGFILE
  22. INNOBACKUPEX = "/usr/bin/innobackupex"
  23. ALERTMAIL = "EMAILADDRESS@ADDRESS.COM" #to use multiple recepients, this needs to be turned into a list ["email1@bla.com", "email2@bla.com", "email3@bla.com", ...]
  24.  
  25.  
  26. #backup configuration
  27. #to use one binary over other, please put it at the start of the list, if it doesnt exist it will get skipped
  28. COMPRESS = ["/usr/bin/pbzip2","/usr/local/sbin/pbzip2","/usr/bin/pigz","/usr/local/sbin/pigz"]
  29. BACKUPDIR = '/home/backups/mysql/'
  30. RETENTION =int(7)
  31. STREAMING = False
  32. PARALEL = "4"
  33. USEMEMORY = "1G"
  34. CUSTOMOPT = "" #separate them with a space between, use syntax same as on the cli "--option=value --option2=value"
  35. COMPRESSOPT = ""
  36.  
  37.  
  38.  
  39. ########Bunch of checks that need to be ran before we proceed
  40. ########
  41. #check which compression to use
  42. compression = ""
  43. for i in range(0, len(COMPRESS)):
  44. if os.path.isfile(COMPRESS[i]):
  45. compression = COMPRESS[i]
  46. break
  47. #exit if compression is not set up
  48. if compression == "":
  49. print ("none of compressions are available, please check which ones are available and which ones are provided")
  50. sys.exit()
  51.  
  52.  
  53. #compression being used:
  54. if ("pbzip2" in compression):
  55. backupSuffix = ".tar.bz2"
  56. elif ("pigz" in compression):
  57. backupSuffix = ".tar.gz"
  58. else:
  59. print ("wrong compression")
  60. sys.exit()
  61.  
  62. #set backupname
  63. createDate = datetime.today().strftime("%Y%m%d-%H%M%S")
  64. if STREAMING:
  65. createName = "mysql_backups_" + HOSTNAME + "_" + createDate + "-streaming"
  66. createNameCompressed = "mysql_backups_" + HOSTNAME + "_" + createDate + "-streaming" + backupSuffix
  67. else:
  68. createName = "mysql_backups_" + HOSTNAME + "_" + createDate
  69. createNameCompressed = "mysql_backups_" + HOSTNAME + "_" + createDate + backupSuffix
  70.  
  71. #get mysql datadir
  72. commandToRun = "mysql -e 'select @@datadir;'"
  73. args = shlex.split(commandToRun)
  74. p = subprocess.Popen(args, stdout=subprocess.PIPE)
  75. DATADIR = p.stdout.read().splitlines()[-1]
  76. p.communicate()
  77. #print (output.splitlines()[-1])
  78. print (DATADIR)
  79. if os.path.isdir(DATADIR) is False:
  80. print (DATADIR + "does not exit")
  81. sys.exit()
  82.  
  83.  
  84. #check if it is slave
  85. commandToRun = "mysql -e 'show slave status\G'"
  86. args = shlex.split(commandToRun)
  87. p = subprocess.Popen(args, stdout=subprocess.PIPE)
  88. ISSLAVE = p.stdout.read()
  89. p.communicate()
  90. #if the machine is a slave add --slave-info to options
  91. if ISSLAVE:
  92. CUSTOMOPT += " --no-timestamp --slave-info "
  93. else:
  94. CUSTOMOPT += " --no-timestamp "
  95.  
  96.  
  97. #the fun starts here - Tuborg
  98. #skip disk check if .skipcheck is present in backupdir, remove after the run
  99. def startBackups():
  100. if os.path.isfile(BACKUPDIR + ".skipcheck"):
  101. now = datetime.today().strftime("%Y-%m-%d %H:%M:%S")
  102. print(now + ": Skipping prerun disk space checks and running backups. skipcheck file will be removed")
  103. #function that runs backups
  104. os.remove(BACKUPDIR + ".skipcheck")
  105. runBackup()
  106. else:
  107. isRunnable()
  108.  
  109. #check total freeDisk disk space on partition containting BACKUPDIR, in bytes
  110. def freeSpace(BACKUPDIR):
  111. st = os.statvfs(BACKUPDIR)
  112. freeDisk = int(st.f_bavail * st.f_frsize)
  113. return freeDisk
  114.  
  115. #get the size of the backup specified
  116. def listBackups(BACKUPDIR, backupSuffix):
  117. backupNameRegex = os.path.join(BACKUPDIR + 'mysql_backups_' + HOSTNAME + '_' + '*' + backupSuffix)
  118. listBackups = glob.glob(backupNameRegex)
  119. return listBackups
  120.  
  121. #checks the site of the latest backup
  122. def lastBackupSize():
  123. backupNames = listBackups(BACKUPDIR, backupSuffix)
  124. print (backupNames)
  125. if not backupNames:
  126. lastSize = 0
  127. else:
  128. lastSize = os.path.getsize(max(backupNames , key = os.path.getctime))
  129. return lastSize
  130.  
  131. #get size of the mysql datadir
  132. def dirSize(path):
  133. total_size = 0
  134. for dirpath, dirnames, filenames in os.walk(path):
  135. for f in filenames:
  136. fp = os.path.join(dirpath, f)
  137. total_size += os.path.getsize(fp)
  138. return total_size
  139.  
  140. #prerun checks
  141. def isRunnable():
  142. oldAge = 1
  143. lastSize = lastBackupSize()
  144. freeDisk = freeSpace(BACKUPDIR)
  145. #if streaming backup, we dont care about size of the datadir
  146. if STREAMING:
  147. datadirSize = 0
  148. else:
  149. datadirSize = dirSize(DATADIR)
  150. print("Size of last backup")
  151. print(lastSize)
  152. print("Free disk size")
  153. print(freeDisk)
  154. print("Datadir size")
  155. print(datadirSize)
  156. if ((freeDisk - lastSize - datadirSize) * 1.1) < (lastSize + datadirSize):
  157. sendMail("Cant run backups as there is not enough free disk space")
  158. print("All gucci")
  159. runBackup()
  160.  
  161. #removal of old backups
  162. def removeOldBackups():
  163. #get list of all current backups
  164. listAllBackups = sorted(listBackups(BACKUPDIR, backupSuffix), reverse=True)
  165. print (listAllBackups)
  166. backupsToRemove = listAllBackups[RETENTION:]
  167. print (backupsToRemove)
  168. for i in backupsToRemove:
  169. print(i)
  170. os.remove(i)
  171.  
  172. #start with the backup process
  173. def runBackup():
  174. print("runBackup")
  175. #start regular backups
  176. if not STREAMING:
  177. commandToRun = "nice -n 19 " + INNOBACKUPEX + " " + CUSTOMOPT + "--parallel=" + PARALEL + " " + BACKUPDIR + createName
  178. args = shlex.split(commandToRun)
  179. with open("/tmp/innobackupex.stdout.log", "a+") as f_stdout, open("/tmp/innobackupex.stderr.log", "a+") as f_stderr:
  180. p = subprocess.Popen(args, stdout=f_stdout, stderr=f_stderr)
  181. p.communicate()
  182. #check if backup was successful
  183. lastline = file("/tmp/innobackupex.stderr.log", "r").readlines()[-1]
  184. if not re.search("completed OK!", lastline):
  185. sendMail("Innobackupex failed, more information can be found in the log")
  186. print("innobackupex made it to the otherside")
  187. print("apply log now")
  188.  
  189. #apply log to backup
  190. commandToRun = "nice -n 19 " + INNOBACKUPEX + " " + "--apply-log " + "--use-memory=" + USEMEMORY + " " + BACKUPDIR + createName
  191. print(commandToRun)
  192. args = shlex.split(commandToRun)
  193. print(args)
  194. with open("/tmp/apply.innobackupex.stdout.log", "a+") as f_stdout, open("/tmp/apply.innobackupex.stderr.log", "a+") as f_stderr:
  195. p = subprocess.Popen(args, stdout=f_stdout, stderr=f_stderr)
  196. p.communicate()
  197.  
  198. #check if appylog was successful
  199. lastline = file("/tmp/apply.innobackupex.stderr.log", "r").readlines()[-1]
  200. if not re.search("completed OK!", lastline):
  201. sendMail("Innobackupex failed at applying log, more information can be found in the log")
  202.  
  203. #compress mysql configs as well
  204. commandToRun = "tar -cz /etc/mysql/"
  205. print (commandToRun)
  206. args = shlex.split(commandToRun)
  207. print(args)
  208. with open(BACKUPDIR + createName + "/etc-mysql.tar.gz", "a+") as f_stdout, open("/tmp/tar_error.log", "a+") as f_stderr:
  209. p = subprocess.Popen(args, stdout=f_stdout, stderr=f_stderr)
  210. p.communicate()
  211.  
  212. #compress the backed up directory
  213. with open(BACKUPDIR + createNameCompressed, "a+") as f_stdout, open("/tmp/tar_error.log", "a+") as tar_stderr:
  214. tarItUp = "tar -v -c " + BACKUPDIR + createName
  215. argsTar = shlex.split(tarItUp)
  216. p1 = subprocess.Popen(argsTar, stdout=subprocess.PIPE, stderr=tar_stderr)
  217. compressItUp = "nice -n 19 " + compression + COMPRESSOPT + " -c "
  218. argsCompress = shlex.split(compressItUp)
  219. p2 = subprocess.Popen(argsCompress, stdin=p1.stdout, stdout=f_stdout, stderr=tar_stderr)
  220. p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.
  221. p2.communicate()
  222. exitcodep2 = p2.returncode
  223. if exitcodep2 != 0:
  224. sendMail("Compression of backup has failed. Please check")
  225. try:
  226. shutil.rmtree(BACKUPDIR + createName)
  227. except:
  228. sendMail("Removal of the backupdir failed, please check. Tried to removed the following directory: " + BACKUPDIR + createName)
  229. #start streaming backup
  230. else:
  231. print("stuff")
  232. with open(BACKUPDIR + createNameCompressed, "a+") as f_stdout, open("/tmp/tar_error.log", "a+") as tar_stderr, open("/tmp/innobackupex.stderr.log", "a+") as inno_stderr:
  233. commandToRun = "nice -n 19 " + INNOBACKUPEX + " " + CUSTOMOPT + "--stream=tar" + " " + DATADIR
  234. argsCTR = shlex.split(commandToRun)
  235. print (argsCTR)
  236. print(commandToRun)
  237. p1 = subprocess.Popen(argsCTR, stdout=subprocess.PIPE, stderr=inno_stderr)
  238. compressItUp = compression + " " + COMPRESSOPT + " -c "
  239. argsCompress = shlex.split(compressItUp)
  240. p2 = subprocess.Popen(argsCompress, stdin=p1.stdout, stdout=f_stdout, stderr=tar_stderr)
  241. p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.
  242. p2.communicate()
  243.  
  244. lastline = file("/tmp/innobackupex.stderr.log", "r").readlines()[-1]
  245. if not re.search("completed OK!", lastline):
  246. sendMail("Innobackupex failed on streaming backup, more information can be found in the log")
  247.  
  248. removeOldBackups()
  249. try:
  250. shutil.rmtree(LOCKDIR)
  251. except:
  252. sendMail("unable to remove lockdir")
  253.  
  254.  
  255. #sendmail and exit function
  256. def sendMail(msgBody):
  257. sender = 'root@' + HOSTNAME
  258. receivers = ALERTMAIL
  259. msgBody = msgBody
  260.  
  261. #print ("this works")
  262. #message = """From: """ + sender + """\nTo: """ + receivers + """\nSubject: backup failed on """ + HOSTNAME + """\n\n""" + msgBody + """\n"""
  263.  
  264. #its still ugly, but ugly in mutliple lines
  265. message = ("From: " + sender + "\n"
  266. "To:" + receivers + "\n"
  267. "Subject: Backup failed on " + HOSTNAME + "\n\n"
  268. #"Subject: innobkp.sh on " + HOSTNAME + " has failed!!!" + "\n\n"
  269. + msgBody + "\n")
  270.  
  271. #set smtp out server here:
  272. smtpObj = smtplib.SMTP('')
  273. smtpObj.sendmail(sender, receivers, message)
  274. print ("Successfully sent email")
  275. sys.exit()
  276.  
  277. try:
  278. if not os.path.exists(LOCKDIR):
  279. os.makedirs(LOCKDIR)
  280. startBackups()
  281. else:
  282. print (LOCKDIR + " already exists, script exiting")
  283. sendMail(LOCKDIR + " already exists, backup can not start. Please check logs")
  284. except Exception as err:
  285. sendMail("Unexpected error please check, \n" + err)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement