mirror of
				https://github.com/usmannasir/cyberpanel.git
				synced 2025-10-31 18:36:17 +01:00 
			
		
		
		
	
		
			
	
	
		
			394 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			394 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|  | #!/usr/local/CyberCP/bin/python | ||
|  | import os,sys | ||
|  | sys.path.append('/usr/local/CyberCP') | ||
|  | import django | ||
|  | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings") | ||
|  | django.setup() | ||
|  | import threading as multi | ||
|  | from plogical.processUtilities import ProcessUtilities | ||
|  | import time | ||
|  | from .models import IncJob, JobSnapshots | ||
|  | from websiteFunctions.models import Websites | ||
|  | import plogical.randomPassword as randomPassword | ||
|  | from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging | ||
|  | from xml.etree.ElementTree import Element, SubElement | ||
|  | from xml.etree import ElementTree | ||
|  | from xml.dom import minidom | ||
|  | from backup.models import DBUsers | ||
|  | import plogical.mysqlUtilities as mysqlUtilities | ||
|  | from plogical.backupUtilities import backupUtilities | ||
|  | from plogical.dnsUtilities import DNS | ||
|  | from mailServer.models import Domains as eDomains | ||
|  | from random import randint | ||
|  | 
 | ||
|  | 
 | ||
|  | class IncJobs(multi.Thread): | ||
|  | 
 | ||
|  |     def __init__(self, function, extraArgs): | ||
|  |         multi.Thread.__init__(self) | ||
|  |         self.function = function | ||
|  |         self.extraArgs = extraArgs | ||
|  |         self.repoPath = '' | ||
|  |         self.passwordFile = '' | ||
|  |         self.statusPath = '' | ||
|  |         self.website = '' | ||
|  |         self.backupDestinations = '' | ||
|  |         self.jobid = 0 | ||
|  | 
 | ||
|  |     def run(self): | ||
|  | 
 | ||
|  |         if self.function == 'createBackup': | ||
|  |             self.createBackup() | ||
|  | 
 | ||
|  |     def prepareBackupMeta(self): | ||
|  |         try: | ||
|  | 
 | ||
|  |             ######### Generating meta | ||
|  | 
 | ||
|  |             ## XML Generation | ||
|  | 
 | ||
|  |             metaFileXML = Element('metaFile') | ||
|  | 
 | ||
|  |             child = SubElement(metaFileXML, 'masterDomain') | ||
|  |             child.text = self.website.domain | ||
|  | 
 | ||
|  |             child = SubElement(metaFileXML, 'phpSelection') | ||
|  |             child.text = self.website.phpSelection | ||
|  | 
 | ||
|  |             child = SubElement(metaFileXML, 'externalApp') | ||
|  |             child.text = self.website.externalApp | ||
|  | 
 | ||
|  |             childDomains = self.website.childdomains_set.all() | ||
|  | 
 | ||
|  |             databases = self.website.databases_set.all() | ||
|  | 
 | ||
|  |             ## Child domains XML | ||
|  | 
 | ||
|  |             childDomainsXML = Element('ChildDomains') | ||
|  | 
 | ||
|  |             for items in childDomains: | ||
|  |                 childDomainXML = Element('domain') | ||
|  | 
 | ||
|  |                 child = SubElement(childDomainXML, 'domain') | ||
|  |                 child.text = items.domain | ||
|  |                 child = SubElement(childDomainXML, 'phpSelection') | ||
|  |                 child.text = items.phpSelection | ||
|  |                 child = SubElement(childDomainXML, 'path') | ||
|  |                 child.text = items.path | ||
|  | 
 | ||
|  |                 childDomainsXML.append(childDomainXML) | ||
|  | 
 | ||
|  |             metaFileXML.append(childDomainsXML) | ||
|  | 
 | ||
|  |             ## Databases XML | ||
|  | 
 | ||
|  |             databasesXML = Element('Databases') | ||
|  | 
 | ||
|  |             for items in databases: | ||
|  |                 try: | ||
|  |                     dbuser = DBUsers.objects.get(user=items.dbUser) | ||
|  |                     userToTry = items.dbUser | ||
|  |                 except: | ||
|  |                     dbusers = DBUsers.objects.all().filter(user=items.dbUser) | ||
|  |                     userToTry = items.dbUser | ||
|  |                     for it in dbusers: | ||
|  |                         dbuser = it | ||
|  |                         break | ||
|  | 
 | ||
|  |                     userToTry = mysqlUtilities.mysqlUtilities.fetchuser(items.dbName) | ||
|  | 
 | ||
|  |                     try: | ||
|  |                         dbuser = DBUsers.objects.get(user=userToTry) | ||
|  |                     except: | ||
|  |                         dbusers = DBUsers.objects.all().filter(user=userToTry) | ||
|  |                         for it in dbusers: | ||
|  |                             dbuser = it | ||
|  |                             break | ||
|  | 
 | ||
|  |                 databaseXML = Element('database') | ||
|  | 
 | ||
|  |                 child = SubElement(databaseXML, 'dbName') | ||
|  |                 child.text = items.dbName | ||
|  |                 child = SubElement(databaseXML, 'dbUser') | ||
|  |                 child.text = userToTry | ||
|  |                 child = SubElement(databaseXML, 'password') | ||
|  |                 child.text = dbuser.password | ||
|  | 
 | ||
|  |                 databasesXML.append(databaseXML) | ||
|  | 
 | ||
|  |             metaFileXML.append(databasesXML) | ||
|  | 
 | ||
|  |             ## Get Aliases | ||
|  | 
 | ||
|  |             aliasesXML = Element('Aliases') | ||
|  | 
 | ||
|  |             aliases = backupUtilities.getAliases(self.website.domain) | ||
|  | 
 | ||
|  |             for items in aliases: | ||
|  |                 child = SubElement(aliasesXML, 'alias') | ||
|  |                 child.text = items | ||
|  | 
 | ||
|  |             metaFileXML.append(aliasesXML) | ||
|  | 
 | ||
|  |             ## Finish Alias | ||
|  | 
 | ||
|  |             ## DNS Records XML | ||
|  | 
 | ||
|  |             try: | ||
|  | 
 | ||
|  |                 dnsRecordsXML = Element("dnsrecords") | ||
|  |                 dnsRecords = DNS.getDNSRecords(self.website.domain) | ||
|  | 
 | ||
|  |                 for items in dnsRecords: | ||
|  |                     dnsRecordXML = Element('dnsrecord') | ||
|  | 
 | ||
|  |                     child = SubElement(dnsRecordXML, 'type') | ||
|  |                     child.text = items.type | ||
|  |                     child = SubElement(dnsRecordXML, 'name') | ||
|  |                     child.text = items.name | ||
|  |                     child = SubElement(dnsRecordXML, 'content') | ||
|  |                     child.text = items.content | ||
|  |                     child = SubElement(dnsRecordXML, 'priority') | ||
|  |                     child.text = str(items.prio) | ||
|  | 
 | ||
|  |                     dnsRecordsXML.append(dnsRecordXML) | ||
|  | 
 | ||
|  |                 metaFileXML.append(dnsRecordsXML) | ||
|  | 
 | ||
|  |             except BaseException as msg: | ||
|  |                 logging.statusWriter(self.statusPath, '%s. [158:prepMeta]' % (str(msg)), 1) | ||
|  | 
 | ||
|  |             ## Email accounts XML | ||
|  | 
 | ||
|  |             try: | ||
|  |                 emailRecordsXML = Element('emails') | ||
|  |                 eDomain = eDomains.objects.get(domain=self.website.domain) | ||
|  |                 emailAccounts = eDomain.eusers_set.all() | ||
|  | 
 | ||
|  |                 for items in emailAccounts: | ||
|  |                     emailRecordXML = Element('emailAccount') | ||
|  | 
 | ||
|  |                     child = SubElement(emailRecordXML, 'email') | ||
|  |                     child.text = items.email | ||
|  |                     child = SubElement(emailRecordXML, 'password') | ||
|  |                     child.text = items.password | ||
|  | 
 | ||
|  |                     emailRecordsXML.append(emailRecordXML) | ||
|  | 
 | ||
|  |                 metaFileXML.append(emailRecordsXML) | ||
|  |             except BaseException as msg: | ||
|  |                 logging.writeToFile(self.statusPath, '%s. [warning:179:prepMeta]' % (str(msg)), 1) | ||
|  | 
 | ||
|  |             ## Email meta generated! | ||
|  | 
 | ||
|  |             def prettify(elem): | ||
|  |                 """Return a pretty-printed XML string for the Element.
 | ||
|  |                 """
 | ||
|  |                 rough_string = ElementTree.tostring(elem, 'utf-8') | ||
|  |                 reparsed = minidom.parseString(rough_string) | ||
|  |                 return reparsed.toprettyxml(indent="  ") | ||
|  | 
 | ||
|  |             ## /home/example.com/backup/backup-example-06-50-03-Thu-Feb-2018/meta.xml -- metaPath | ||
|  | 
 | ||
|  |             metaPath = '/home/cyberpanel/%s' % (str(randint(1000, 9999))) | ||
|  | 
 | ||
|  |             xmlpretty = prettify(metaFileXML).encode('ascii', 'ignore') | ||
|  |             metaFile = open(metaPath, 'w') | ||
|  |             metaFile.write(xmlpretty) | ||
|  |             metaFile.close() | ||
|  |             os.chmod(metaPath, 0o640) | ||
|  | 
 | ||
|  |             ## meta generated | ||
|  | 
 | ||
|  |             logging.statusWriter(self.statusPath, 'Meta data is ready..', 1) | ||
|  | 
 | ||
|  |             metaPathNew = '/home/%s/meta.xml' % (self.website.domain) | ||
|  |             command = 'mv %s %s' % (metaPath, metaPathNew) | ||
|  |             ProcessUtilities.executioner(command) | ||
|  | 
 | ||
|  |             command = 'chown %s:%s %s' % (self.website.externalApp, self.website.externalApp, metaPathNew) | ||
|  |             ProcessUtilities.executioner(command) | ||
|  | 
 | ||
|  |             return 1 | ||
|  | 
 | ||
|  |         except BaseException as msg: | ||
|  |             logging.statusWriter(self.statusPath, "%s [207][5009]" % (str(msg)), 1) | ||
|  |             return 0 | ||
|  | 
 | ||
|  |     def backupData(self): | ||
|  |         try: | ||
|  |             logging.statusWriter(self.statusPath, 'Backing up data..', 1) | ||
|  | 
 | ||
|  |             backupPath = '/home/%s' % (self.website.domain) | ||
|  |             # Define our excludes file for use with restic | ||
|  |             backupExcludesFile = '/home/%s/backup-exclude.conf' % (self.website.domain) | ||
|  |             resticBackupExcludeCMD = ' --exclude-file=%s' % (backupExcludesFile) | ||
|  | 
 | ||
|  |             if self.backupDestinations == 'local': | ||
|  |                 command = 'restic -r %s backup %s --password-file %s --exclude %s' % (self.repoPath, backupPath, self.passwordFile, self.repoPath) | ||
|  |                 # If /home/%s/backup-exclude.conf file exists lets pass this to restic by appending the command to end. | ||
|  |                 if os.path.isfile(backupExcludesFile): | ||
|  |                     command = command + resticBackupExcludeCMD | ||
|  |                 snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] | ||
|  | 
 | ||
|  |                 newSnapshot = JobSnapshots(job=self.jobid, type='data:%s' % (backupPath), snapshotid=snapShotid, destination=self.backupDestinations) | ||
|  |                 newSnapshot.save() | ||
|  | 
 | ||
|  | 
 | ||
|  |             elif self.backupDestinations[:4] == 'sftp': | ||
|  |                 remotePath = '/home/backup/%s' % (self.website.domain) | ||
|  |                 command = 'export PATH=${PATH}:/usr/bin && restic -r %s:%s backup %s --password-file %s --exclude %s' % (self.backupDestinations, remotePath, backupPath, self.passwordFile, self.repoPath) | ||
|  |                 # If /home/%s/backup-exclude.conf file exists lets pass this to restic by appending the command to end. | ||
|  |                 if os.path.isfile(backupExcludesFile): | ||
|  |                     command = command + resticBackupExcludeCMD | ||
|  |                 snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] | ||
|  |                 newSnapshot = JobSnapshots(job=self.jobid, type='data:%s' % (remotePath), snapshotid=snapShotid, | ||
|  |                                            destination=self.backupDestinations) | ||
|  |                 newSnapshot.save() | ||
|  | 
 | ||
|  |             logging.statusWriter(self.statusPath, 'Data for %s backed to %s.' % (self.website.domain, self.backupDestinations), 1) | ||
|  |             return 1 | ||
|  |         except BaseException as msg: | ||
|  |             logging.statusWriter(self.statusPath,'%s. [IncJobs.backupData.223][5009]' % str(msg), 1) | ||
|  |             return 0 | ||
|  | 
 | ||
|  |     def backupDatabases(self): | ||
|  |         try: | ||
|  |             logging.statusWriter(self.statusPath, 'Backing up databases..', 1) | ||
|  | 
 | ||
|  |             databases = self.website.databases_set.all() | ||
|  | 
 | ||
|  |             for items in databases: | ||
|  |                 if mysqlUtilities.mysqlUtilities.createDatabaseBackup(items.dbName, '/home/cyberpanel') == 0: | ||
|  |                     return 0 | ||
|  | 
 | ||
|  |                 dbPath = '/home/cyberpanel/%s.sql' % (items.dbName) | ||
|  | 
 | ||
|  |                 if self.backupDestinations == 'local': | ||
|  |                     command = 'restic -r %s backup %s --password-file %s' % (self.repoPath, dbPath, self.passwordFile) | ||
|  |                     snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] | ||
|  | 
 | ||
|  |                     newSnapshot = JobSnapshots(job=self.jobid, type='database:%s' % (items.dbName), snapshotid=snapShotid, destination=self.backupDestinations) | ||
|  |                     newSnapshot.save() | ||
|  | 
 | ||
|  |                 elif self.backupDestinations[:4] == 'sftp': | ||
|  |                     remotePath = '/home/backup/%s' % (self.website.domain) | ||
|  |                     command = 'export PATH=${PATH}:/usr/bin && restic -r %s:%s backup %s --password-file %s --exclude %s' % ( | ||
|  |                     self.backupDestinations, remotePath, dbPath, self.passwordFile, self.repoPath) | ||
|  |                     snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] | ||
|  |                     newSnapshot = JobSnapshots(job=self.jobid, type='database:%s' % (items.dbName), snapshotid=snapShotid, | ||
|  |                                                destination=self.backupDestinations) | ||
|  |                     newSnapshot.save() | ||
|  |             return 1 | ||
|  |         except BaseException as msg: | ||
|  |             logging.statusWriter(self.statusPath,'%s. [IncJobs.backupDatabases.269][5009]' % str(msg), 1) | ||
|  |             return 0 | ||
|  | 
 | ||
|  |     def emailBackup(self): | ||
|  |         try: | ||
|  |             logging.statusWriter(self.statusPath, 'Backing up emails..', 1) | ||
|  | 
 | ||
|  |             backupPath = '/home/vmail/%s' % (self.website.domain) | ||
|  | 
 | ||
|  |             if os.path.exists(backupPath): | ||
|  |                 if self.backupDestinations == 'local': | ||
|  |                     logging.statusWriter(self.statusPath, 'hello world', 1) | ||
|  |                     command = 'restic -r %s backup %s --password-file %s' % ( | ||
|  |                     self.repoPath, backupPath, self.passwordFile) | ||
|  |                     snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] | ||
|  | 
 | ||
|  |                     newSnapshot = JobSnapshots(job=self.jobid, type='email:%s' % (backupPath), snapshotid=snapShotid, | ||
|  |                                                destination=self.backupDestinations) | ||
|  |                     newSnapshot.save() | ||
|  |                     logging.statusWriter(self.statusPath, 'hello world 2', 1) | ||
|  | 
 | ||
|  |                 elif self.backupDestinations[:4] == 'sftp': | ||
|  |                     remotePath = '/home/backup/%s' % (self.website.domain) | ||
|  |                     command = 'export PATH=${PATH}:/usr/bin && restic -r %s:%s backup %s --password-file %s --exclude %s' % ( | ||
|  |                         self.backupDestinations, remotePath, backupPath, self.passwordFile, self.repoPath) | ||
|  |                     snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] | ||
|  |                     newSnapshot = JobSnapshots(job=self.jobid, type='email:%s' % (backupPath), snapshotid=snapShotid, | ||
|  |                                                destination=self.backupDestinations) | ||
|  |                     newSnapshot.save() | ||
|  | 
 | ||
|  |             logging.statusWriter(self.statusPath, 'Emails for %s backed to %s.' % (self.website.domain, self.backupDestinations), 1) | ||
|  |             return 1 | ||
|  |         except BaseException as msg: | ||
|  |             logging.statusWriter(self.statusPath,'%s. [IncJobs.backupDatabases.269][5009]' % str(msg), 1) | ||
|  |             return 0 | ||
|  | 
 | ||
|  |     def initiateRepo(self): | ||
|  |         try: | ||
|  |             logging.statusWriter(self.statusPath, 'Will first initiate backup repo..', 1) | ||
|  | 
 | ||
|  |             # Define our excludes file for use with restic | ||
|  |             backupExcludesFile = '/home/%s/backup-exclude.conf' % (self.website.domain) | ||
|  |             resticBackupExcludeCMD = ' --exclude-file=%s' % (backupExcludesFile) | ||
|  | 
 | ||
|  |             if self.backupDestinations == 'local': | ||
|  |                 command = 'restic init --repo %s --password-file %s' % (self.repoPath, self.passwordFile) | ||
|  |                 # If /home/%s/backup-exclude.conf file exists lets pass this to restic by appending the command to end. | ||
|  |                 if os.path.isfile(backupExcludesFile): | ||
|  |                     command = command + resticBackupExcludeCMD | ||
|  |                 ProcessUtilities.executioner(command, self.website.externalApp) | ||
|  | 
 | ||
|  |             elif self.backupDestinations[:4] == 'sftp': | ||
|  |                 remotePath = '/home/backup/%s' % (self.website.domain) | ||
|  |                 command = 'export PATH=${PATH}:/usr/bin && restic init --repo %s:%s --password-file %s' % (self.backupDestinations, remotePath, self.passwordFile) | ||
|  |                 # If /home/%s/backup-exclude.conf file exists lets pass this to restic by appending the command to end. | ||
|  |                 if os.path.isfile(backupExcludesFile): | ||
|  |                     command = command + resticBackupExcludeCMD | ||
|  |                 ProcessUtilities.executioner(command) | ||
|  | 
 | ||
|  |             logging.statusWriter(self.statusPath, 'Repo %s initiated for %s.' % (self.backupDestinations, self.website.domain), 1) | ||
|  |             return 1 | ||
|  |         except BaseException as msg: | ||
|  |             logging.statusWriter(self.statusPath,'%s. [IncJobs.initiateRepo.47][5009]' % str(msg), 1) | ||
|  |             return 0 | ||
|  | 
 | ||
|  |     def createBackup(self): | ||
|  |         self.statusPath = self.extraArgs['tempPath'] | ||
|  |         website = self.extraArgs['website'] | ||
|  |         self.backupDestinations = self.extraArgs['backupDestinations'] | ||
|  |         websiteData = self.extraArgs['websiteData'] | ||
|  |         websiteEmails = self.extraArgs['websiteEmails'] | ||
|  |         websiteSSLs = self.extraArgs['websiteSSLs'] | ||
|  |         websiteDatabases = self.extraArgs['websiteDatabases'] | ||
|  | 
 | ||
|  |         self.website = Websites.objects.get(domain=website) | ||
|  | 
 | ||
|  |         newJob = IncJob(website=self.website) | ||
|  |         newJob.save() | ||
|  | 
 | ||
|  |         self.jobid = newJob | ||
|  | 
 | ||
|  |         self.passwordFile = '/home/%s/%s' % (self.website.domain, self.website.domain) | ||
|  |         password = randomPassword.generate_pass() | ||
|  | 
 | ||
|  |         self.repoPath = '/home/%s/incbackup' % (self.website.domain) | ||
|  | 
 | ||
|  |         if not os.path.exists(self.passwordFile): | ||
|  |             command = 'echo "%s" > %s' % (password, self.passwordFile) | ||
|  |             ProcessUtilities.executioner(command, self.website.externalApp) | ||
|  | 
 | ||
|  | 
 | ||
|  |         if self.initiateRepo() == 0: | ||
|  |             return | ||
|  | 
 | ||
|  |         if self.prepareBackupMeta() == 0: | ||
|  |             return | ||
|  | 
 | ||
|  |         if websiteData: | ||
|  |             if self.backupData() == 0: | ||
|  |                 return | ||
|  | 
 | ||
|  |         if websiteDatabases: | ||
|  |             if self.backupDatabases() == 0: | ||
|  |                 return | ||
|  | 
 | ||
|  | 
 | ||
|  |         if websiteEmails: | ||
|  |             if self.emailBackup() == 0: | ||
|  |                 return | ||
|  | 
 | ||
|  |         logging.statusWriter(self.statusPath, 'Completed', 1) |