You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

182 lines
5.0 KiB

  1. """
  2. This module handles the On Demand Backup utility
  3. """
  4. #Imports
  5. import os, webnotes
  6. from datetime import datetime
  7. #Global constants
  8. from webnotes.defs import backup_path, backup_link_path, backup_url
  9. verbose = 0
  10. class BackupGenerator:
  11. """
  12. This class contains methods to perform On Demand Backup
  13. To initialize, specify (db_name, user, password, db_file_name=None)
  14. If specifying db_file_name, also append ".sql.gz"
  15. """
  16. def __init__(self, db_name, user, password, db_file_name=None):
  17. self.db_name = db_name
  18. self.user = user
  19. self.password = password
  20. self.db_file_name = db_file_name and db_file_name \
  21. or (backup_path + db_name + ".sql.gz")
  22. def take_dump(self):
  23. """
  24. Dumps a db via mysqldump
  25. """
  26. os.system("""mysqldump -u %(user)s -p%(password)s %(db_name)s |
  27. gzip -c > %(db_file_name)s""" % self.__dict__)
  28. def copy_to_backup_link(self):
  29. """
  30. Copies the backup file from backup path to shared link path
  31. It also gives the file a random name, thus hiding the db_name
  32. """
  33. import random
  34. todays_date = "".join(str(datetime.date(datetime.today())).split("-"))
  35. random_number = str(int(random.random()*99999999))
  36. #Generate a random name using today's date and a 8 digit random number
  37. random_name = todays_date + "_" + random_number + ".sql.gz"
  38. os.system("""cp -f %(src_file)s %(dest_file)s""" % \
  39. {"src_file":self.db_file_name,
  40. "dest_file":(backup_link_path + random_name)})
  41. if verbose: print "file copied"
  42. return random_name
  43. def get_recipients(self):
  44. """
  45. Get recepient's email address
  46. """
  47. import webnotes.db
  48. webnotes.conn = webnotes.db.Database(use_default = 1)
  49. recipient_list = webnotes.conn.sql("""SELECT parent FROM tabUserRole
  50. WHERE role='System Manager'
  51. AND parent!='Administrator'""")
  52. return [i[0] for i in recipient_list]
  53. def send_email(self, backup_file):
  54. """
  55. Sends the link to backup file located at erpnext/backups
  56. """
  57. file_url = backup_url + backup_file
  58. from webnotes.utils.email_lib import sendmail
  59. recipient_list = self.get_recipients()
  60. msg = """<a href=%(file_url)s>Click here to begin downloading\
  61. your backup</a>
  62. This link will be valid for 24 hours.
  63. Also, a new backup will be available for download (if requested)\
  64. only after 24 hours.""" % {"file_url":file_url}
  65. datetime_str = datetime.fromtimestamp(os.stat(self.db_file_name).st_ctime)
  66. subject = datetime_str.strftime("%d/%m/%Y %H:%M:%S") + """ - Backup ready to be downloaded"""
  67. sendmail(recipients=recipient_list, msg=msg, subject=subject)
  68. def get_backup(self):
  69. """
  70. Takes a new dump if existing file is old
  71. and sends the link to the file as email
  72. """
  73. #Check if file exists and is less than a day old
  74. #If not Take Dump
  75. if is_file_old(self.db_file_name):
  76. self.take_dump()
  77. #Copy file to backup_link_path
  78. #This is a security hole. When the user calls get_backup repeatedly
  79. #a file will be generated each time.
  80. backup_file = self.copy_to_backup_link()
  81. #Email Link
  82. self.send_email(backup_file)
  83. def get_backup():
  84. """
  85. This function is executed when the user clicks on
  86. Toos > Download Backup
  87. """
  88. #if verbose: print webnotes.conn.cur_db_name + " " + webnotes.defs.db_password
  89. odb = BackupGenerator(webnotes.conn.cur_db_name, webnotes.conn.cur_db_name,\
  90. webnotes.defs.db_password)
  91. odb.get_backup()
  92. webnotes.msgprint("""A download link to your backup will be emailed \
  93. to you shortly.""")
  94. def delete_temp_backups():
  95. """
  96. Cleans up the backup_link_path directory by deleting files older than 24 hours
  97. """
  98. file_list = os.listdir(backup_link_path)
  99. for this_file in file_list:
  100. this_file_path = backup_link_path + this_file
  101. if is_file_old(this_file_path, 1):
  102. os.remove(this_file_path)
  103. def is_file_old(db_file_name, older_than=24):
  104. """
  105. Checks if file exists and is older than specified hours
  106. Returns ->
  107. True: file does not exist or file is old
  108. False: file is new
  109. """
  110. if os.path.isfile(db_file_name):
  111. from datetime import timedelta
  112. import time
  113. #Get timestamp of the file
  114. file_datetime = datetime.fromtimestamp\
  115. (os.stat(db_file_name).st_ctime)
  116. if datetime.today() - file_datetime >= timedelta(hours = older_than):
  117. if verbose: print "File is old"
  118. return True
  119. else:
  120. if verbose: print "File is recent"
  121. return False
  122. else:
  123. if verbose: print "File does not exist"
  124. return True
  125. if __name__ == "__main__":
  126. """
  127. is_file_old db_name user password
  128. get_backup db_name user password
  129. """
  130. import sys
  131. cmd = sys.argv[1]
  132. if cmd == "is_file_old":
  133. odb = BackupGenerator(sys.argv[2], sys.argv[3], sys.argv[4])
  134. is_file_old(odb.db_file_name)
  135. if cmd == "get_backup":
  136. odb = BackupGenerator(sys.argv[2], sys.argv[3], sys.argv[4])
  137. odb.get_backup()
  138. if cmd == "take_dump":
  139. odb = BackupGenerator(sys.argv[2], sys.argv[3], sys.argv[4])
  140. odb.take_dump()
  141. if cmd == "send_email":
  142. odb = BackupGenerator(sys.argv[2], sys.argv[3], sys.argv[4])
  143. odb.send_email("abc.sql.gz")
  144. if cmd == "delete_temp_backups":
  145. delete_temp_backups()