From 0d92c2e7f8b920f46886b28d6f1362b5a85fab55 Mon Sep 17 00:00:00 2001 From: RisvanaCybro Date: Wed, 30 Oct 2024 17:15:29 +0530 Subject: [PATCH] Oct 30: [FIX] Bug Fixed 'auto_database_backup' --- auto_database_backup/__manifest__.py | 6 +- auto_database_backup/doc/RELEASE_NOTES.md | 5 ++ .../models/db_backup_configure.py | 86 ++++++++++++++++--- 3 files changed, 84 insertions(+), 13 deletions(-) diff --git a/auto_database_backup/__manifest__.py b/auto_database_backup/__manifest__.py index 84e331821..485ed57e0 100644 --- a/auto_database_backup/__manifest__.py +++ b/auto_database_backup/__manifest__.py @@ -21,7 +21,7 @@ ############################################################################# { 'name': "Automatic Database Backup", - 'version': '14.0.1.0.1', + 'version': '14.0.2.0.2', 'summary': 'Generate automatic backup of databases and store to local, ' 'google drive or remote server', 'description': 'his module has been developed for creating ' @@ -40,8 +40,8 @@ 'wizard/dropbox_auth_code_views.xml' ], 'external_dependencies': { - 'python': ['dropbox', 'pyncclient', 'boto3', 'nextcloud-api-wrapper', - 'paramiko']}, + 'python': ['dropbox', 'pyncclient', 'boto3', 'nextcloud-api-wrapper', 'paramiko'] + }, 'license': 'LGPL-3', 'images': ['static/description/banner.gif'], 'installable': True, diff --git a/auto_database_backup/doc/RELEASE_NOTES.md b/auto_database_backup/doc/RELEASE_NOTES.md index 2b5e852a3..3998972f1 100644 --- a/auto_database_backup/doc/RELEASE_NOTES.md +++ b/auto_database_backup/doc/RELEASE_NOTES.md @@ -24,3 +24,8 @@ #### Version 14.0.1.0.1 #### ADD - Nextcloud and Amazon S3 integration added. Backup can be stored into Nextcloud and Amazon S3. + +#### 24.10.2024 +#### Version 14.0.2.0.2 +#### UPDT +- Fixed the errors while inputting list_db = False in odoo conf file. diff --git a/auto_database_backup/models/db_backup_configure.py b/auto_database_backup/models/db_backup_configure.py index d93e5acc9..24936c751 100644 --- a/auto_database_backup/models/db_backup_configure.py +++ b/auto_database_backup/models/db_backup_configure.py @@ -27,7 +27,8 @@ import logging import os import tempfile from datetime import timedelta - +import shutil +import subprocess import boto3 import dropbox import nextcloud_client @@ -40,6 +41,7 @@ from werkzeug import urls import odoo from odoo import api, fields, models, _ from odoo.exceptions import UserError, ValidationError +from odoo.tools.misc import find_pg_tool, exec_pg_environ from odoo.http import request from odoo.service import db @@ -675,7 +677,7 @@ class AutoDatabaseBackup(models.Model): os.makedirs(rec.backup_path) backup_file = os.path.join(rec.backup_path, backup_filename) f = open(backup_file, "wb") - odoo.service.db.dump_db(rec.db_name, f, rec.backup_format) + self.dump_data(rec.db_name, f, rec.backup_format) f.close() # remove older backups if rec.auto_remove: @@ -708,7 +710,7 @@ class AutoDatabaseBackup(models.Model): ftp_server.mkd(rec.ftp_path) ftp_server.cwd(rec.ftp_path) with open(temp.name, "wb+") as tmp: - odoo.service.db.dump_db(rec.db_name, tmp, + self.dump_data(rec.db_name, tmp, rec.backup_format) ftp_server.storbinary('STOR %s' % backup_filename, open(temp.name, "rb")) @@ -743,7 +745,7 @@ class AutoDatabaseBackup(models.Model): temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: - odoo.service.db.dump_db(rec.db_name, tmp, + self.dump_data(rec.db_name, tmp, rec.backup_format) try: sftp.chdir(rec.sftp_path) @@ -779,7 +781,7 @@ class AutoDatabaseBackup(models.Model): temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: - odoo.service.db.dump_db(rec.db_name, tmp, + self.dump_data(rec.db_name, tmp, rec.backup_format) try: headers = { @@ -839,7 +841,7 @@ class AutoDatabaseBackup(models.Model): temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: - odoo.service.db.dump_db(rec.db_name, tmp, + self.dump_data(rec.db_name, tmp, rec.backup_format) try: dbx = dropbox.Dropbox( @@ -877,7 +879,7 @@ class AutoDatabaseBackup(models.Model): temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: - odoo.service.db.dump_db(rec.db_name, tmp, + self.dump_data(rec.db_name, tmp, rec.backup_format) headers = { 'Authorization': 'Bearer %s' % rec.onedrive_access_token, @@ -989,7 +991,7 @@ class AutoDatabaseBackup(models.Model): temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: - odoo.service.db.dump_db(rec.db_name, tmp, + self.dump_data(rec.db_name, tmp, rec.backup_format) backup_file_path = temp.name remote_file_path = f"/{folder_name}/{rec.db_name}_" \ @@ -1000,7 +1002,7 @@ class AutoDatabaseBackup(models.Model): temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: - odoo.service.db.dump_db(rec.db_name, tmp, + self.dump_data(rec.db_name, tmp, rec.backup_format) backup_file_path = temp.name remote_file_path = f"/{folder_name}/{rec.db_name}_" \ @@ -1060,7 +1062,7 @@ class AutoDatabaseBackup(models.Model): temp = tempfile.NamedTemporaryFile( suffix='.%s' % rec.backup_format) with open(temp.name, "wb+") as tmp: - odoo.service.db.dump_db(rec.db_name, tmp, + self.dump_data(rec.db_name, tmp, rec.backup_format) backup_file_path = temp.name remote_file_path = f"{rec.aws_folder_name}/{rec.db_name}_" \ @@ -1083,3 +1085,67 @@ class AutoDatabaseBackup(models.Model): if rec.notify_user: mail_template_failed.send_mail(rec.id, force_send=True) + + def dump_data(self, db_name, stream, backup_format): + """Dump database `db` into file-like object `stream` if stream is None + return a file object with the dump. """ + + cron_user_id = self.env.ref('auto_database_backup.ir_cron_auto_db_backup').user_id.id + if cron_user_id != self.env.user.id: + _logger.error( + 'Unauthorized database operation. Backups should only be available from the cron job.') + raise ValidationError("Unauthorized database operation. Backups should only be available from the cron job.") + + _logger.info('DUMP DB: %s format %s', db_name, backup_format) + cmd = [find_pg_tool('pg_dump'), '--no-owner', db_name] + env = exec_pg_environ() + if backup_format == 'zip': + with tempfile.TemporaryDirectory() as dump_dir: + filestore = odoo.tools.config.filestore(db_name) + cmd.insert(-1,'--file=' + os.path.join(dump_dir, 'dump.sql')) + subprocess.run(cmd, env=env, stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT, check=True) + if os.path.exists(filestore): + shutil.copytree(filestore, + os.path.join(dump_dir, 'filestore')) + with open(os.path.join(dump_dir, 'manifest.json'), 'w') as fh: + db = odoo.sql_db.db_connect(db_name) + with db.cursor() as cr: + json.dump(self._dump_db_manifest(cr), fh, indent=4) + if stream: + odoo.tools.osutil.zip_dir(dump_dir, stream, + include_dir=False, + fnct_sort=lambda + file_name: file_name != 'dump.sql') + else: + t = tempfile.TemporaryFile() + odoo.tools.osutil.zip_dir(dump_dir, t, include_dir=False, + fnct_sort=lambda + file_name: file_name != 'dump.sql') + t.seek(0) + return t + else: + cmd.insert(-1,'--format=c') + process = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE) + stdout, _ = process.communicate() + if stream: + stream.write(stdout) + else: + return stdout + + def _dump_db_manifest(self, cr): + """ This function generates a manifest dictionary for database dump.""" + pg_version = "%d.%d" % divmod(cr._obj.connection.server_version / 100, 100) + cr.execute( + "SELECT name, latest_version FROM ir_module_module WHERE state = 'installed'") + modules = dict(cr.fetchall()) + manifest = { + 'odoo_dump': '1', + 'db_name': cr.dbname, + 'version': odoo.release.version, + 'version_info': odoo.release.version_info, + 'major_version': odoo.release.major_version, + 'pg_version': pg_version, + 'modules': modules, + } + return manifest