diff --git a/plogical/Backupsv2.py b/plogical/Backupsv2.py index 570d3ba8d..88e0990c1 100644 --- a/plogical/Backupsv2.py +++ b/plogical/Backupsv2.py @@ -43,6 +43,7 @@ class CPBackupsV2: ## Set up the repo name to be used self.repo = f"rclone:{self.data['BackendName']}:{self.data['domain']}" + self.snapshots = [] def FetchSnapShots(self): @@ -106,9 +107,8 @@ pass = {ObsecurePassword} self.buv2.website.BackupLock = 0 self.buv2.website.save() - ## parent is used to link this snapshot with master snapshot - def BackupConfig(self, parent): + def BackupConfig(self): ### Backup config file to rustic command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}' @@ -123,12 +123,38 @@ pass = {ObsecurePassword} command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json' ProcessUtilities.executioner(command) - command = f'rustic -r {self.repo} backup {self.FinalPathRuctic}/config.json --password "" --tag {parent}' - ProcessUtilities.executioner(command, self.website.externalApp) + command = f'rustic -r {self.repo} backup {self.FinalPathRuctic}/config.json --password ""' + result = json.loads(ProcessUtilities.outputExecutioner(command, self.website.externalApp, True).rstrip('\n')) + + try: + SnapShotID = result['id'] ## snapshot id that we need to store in db + files_new = result['summary']['files_new'] ## basically new files in backup + total_duration = result['summary']['total_duration'] ## time taken + + self.snapshots.append(SnapShotID) + + except BaseException as msg: + self.UpdateStatus(f'Backup failed as no snapshot id found, error: {str(msg)}', CPBackupsV2.FAILED) + return 0 command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}/config.json' ProcessUtilities.executioner(command) + + def MergeSnapshots(self): + snapshots = '' + for snapshot in self.snapshots: + snapshots= f'{snapshots} {snapshot}' + + + + command = f'rustic -r {self.repo} merge {snapshots} --password ""' + result = json.loads(ProcessUtilities.outputExecutioner(command, self.website.externalApp, True).rstrip('\n')) + + command = f'rustic -r {self.repo} forget {snapshots} --password ""' + result = json.loads(ProcessUtilities.outputExecutioner(command, self.website.externalApp, True).rstrip('\n')) + + def InitiateBackup(self): from websiteFunctions.models import Websites, Backupsv2 @@ -311,6 +337,8 @@ pass = {ObsecurePassword} command = f"chmod 600 {self.FinalPathRuctic}/config.json" ProcessUtilities.executioner(command) + self.BackupConfig() + self.UpdateStatus('Backup config created,5', CPBackupsV2.RUNNING) except BaseException as msg: @@ -343,6 +371,8 @@ pass = {ObsecurePassword} command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}' ProcessUtilities.executioner(command) + self.MergeSnapshots() + self.UpdateStatus('Completed', CPBackupsV2.COMPLETED) print(self.FinalPath) @@ -432,10 +462,10 @@ pass = {ObsecurePassword} ## Now pack config into same thing - command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json' - ProcessUtilities.executioner(command) + #command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json' + #ProcessUtilities.executioner(command) - command = f'rustic -r {self.repo} backup {CurrentDBPath} {self.FinalPathRuctic}/config.json --password "" --json 2>/dev/null' + command = f'rustic -r {self.repo} backup {CurrentDBPath} --password "" --json 2>/dev/null' print(f'db command rustic: {command}') result = json.loads( ProcessUtilities.outputExecutioner(command, self.website.externalApp, True).rstrip('\n')) @@ -445,6 +475,8 @@ pass = {ObsecurePassword} files_new = result['summary']['files_new'] ## basically new files in backup total_duration = result['summary']['total_duration'] ## time taken + self.snapshots.append(SnapShotID) + ### Config is saved with each database, snapshot of config is attached to db snapshot with parent #self.BackupConfig(SnapShotID) @@ -512,14 +544,14 @@ pass = {ObsecurePassword} source = f'/home/{self.website.domain}' - command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json' - ProcessUtilities.executioner(command) + #command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json' + #ProcessUtilities.executioner(command) ## Pending add user provided folders in the exclude list exclude = f' --exclude-if-present rusticbackup --exclude-if-present logs ' - command = f'rustic -r {self.repo} backup {source} {self.FinalPathRuctic}/config.json --password "" {exclude} --json 2>/dev/null' + command = f'rustic -r {self.repo} backup {source} --password "" {exclude} --json 2>/dev/null' result = json.loads(ProcessUtilities.outputExecutioner(command, self.website.externalApp, True).rstrip('\n')) @@ -528,6 +560,8 @@ pass = {ObsecurePassword} files_new = result['summary']['files_new'] ## basically new files in backup total_duration = result['summary']['total_duration'] ## time taken + self.snapshots.append(SnapShotID) + ### Config is saved with each backup, snapshot of config is attached to data snapshot with parent #self.BackupConfig(SnapShotID) @@ -552,8 +586,8 @@ pass = {ObsecurePassword} command = f'rustic init -r {self.repo} --password ""' ProcessUtilities.executioner(command, self.website.externalApp) - command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json' - ProcessUtilities.executioner(command) + #command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json' + #ProcessUtilities.executioner(command) source = f'/home/vmail/{self.website.domain}' @@ -562,7 +596,7 @@ pass = {ObsecurePassword} exclude = f' --exclude-if-present rusticbackup --exclude-if-present logs ' - command = f'rustic -r {self.repo} backup {source} {self.FinalPathRuctic}/config.json --password "" {exclude} --json 2>/dev/null' + command = f'rustic -r {self.repo} backup {source} --password "" {exclude} --json 2>/dev/null' result = json.loads(ProcessUtilities.outputExecutioner(command, self.website.externalApp, True).rstrip('\n')) @@ -571,6 +605,8 @@ pass = {ObsecurePassword} files_new = result['summary']['files_new'] ## basically new files in backup total_duration = result['summary']['total_duration'] ## time taken + self.snapshots.append(SnapShotID) + ### Config is saved with each email backup, snapshot of config is attached to email snapshot with parent #self.BackupConfig(SnapShotID) diff --git a/plogical/mysqlUtilities.py b/plogical/mysqlUtilities.py index cda8ebb27..62efd3f1c 100755 --- a/plogical/mysqlUtilities.py +++ b/plogical/mysqlUtilities.py @@ -245,7 +245,7 @@ class mysqlUtilities: return str(msg) @staticmethod - def createDatabaseBackup(databaseName, tempStoragePath, rustic=0, RusticRepoName = None, RusticConfigPath = None): + def createDatabaseBackup(databaseName, tempStoragePath, rustic=0, RusticRepoName = None): try: passFile = "/etc/cyberpanel/mysqlPassword" @@ -313,11 +313,24 @@ password=%s else: SHELL = True - command = f'mysqldump --defaults-extra-file=/home/cyberpanel/.my.cnf -u {mysqluser} --host={mysqlhost} --port {mysqlport} --add-drop-table --allow-keywords --complete-insert --quote-names --skip-comments {databaseName} | rustic -r {RusticRepoName} backup --stdin-filename {databaseName}.sql {RusticConfigPath} --password "" --json 2>/dev/null' + command = f'mysqldump --defaults-extra-file=/home/cyberpanel/.my.cnf -u {mysqluser} --host={mysqlhost} --port {mysqlport} --add-drop-table --allow-keywords --complete-insert --quote-names --skip-comments {databaseName} | rustic -r {RusticRepoName} backup --stdin-filename {databaseName}.sql --password "" --json 2>/dev/null' if os.path.exists(ProcessUtilities.debugPath): logging.CyberCPLogFileWriter.writeToFile(command) + result = json.loads( + ProcessUtilities.outputExecutioner(command, None, True).rstrip('\n')) + + try: + SnapShotID = result['id'] ## snapshot id that we need to store in db + files_new = result['summary']['files_new'] ## basically new files in backup + total_duration = result['summary']['total_duration'] ## time taken + + return 1, SnapShotID + + except BaseException as msg: + return 0, str(msg) + return 1