auto_backup: allow to change the format of backup (#1333)
parent
17da338c06
commit
507b351523
|
@ -39,6 +39,11 @@ msgstr ""
|
||||||
msgid "Backup Failed"
|
msgid "Backup Failed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: auto_backup
|
||||||
|
#: model:ir.model.fields,field_description:auto_backup.field_db_backup_backup_format
|
||||||
|
msgid "Backup Format"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: auto_backup
|
#. module: auto_backup
|
||||||
#: model:ir.actions.server,name:auto_backup.ir_cron_backup_scheduler_0_ir_actions_server
|
#: model:ir.actions.server,name:auto_backup.ir_cron_backup_scheduler_0_ir_actions_server
|
||||||
#: model:ir.cron,cron_name:auto_backup.ir_cron_backup_scheduler_0
|
#: model:ir.cron,cron_name:auto_backup.ir_cron_backup_scheduler_0
|
||||||
|
@ -66,25 +71,30 @@ msgstr ""
|
||||||
msgid "Cannot duplicate a configuration."
|
msgid "Cannot duplicate a configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: auto_backup
|
||||||
|
#: model:ir.model.fields,help:auto_backup.field_db_backup_backup_format
|
||||||
|
msgid "Choose the format for this backup."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: auto_backup
|
#. module: auto_backup
|
||||||
#: model:ir.model.fields,help:auto_backup.field_db_backup_method
|
#: model:ir.model.fields,help:auto_backup.field_db_backup_method
|
||||||
msgid "Choose the storage method for this backup."
|
msgid "Choose the storage method for this backup."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: auto_backup
|
#. module: auto_backup
|
||||||
#: code:addons/auto_backup/models/db_backup.py:249
|
#: code:addons/auto_backup/models/db_backup.py:265
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Cleanup of old database backups failed."
|
msgid "Cleanup of old database backups failed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: auto_backup
|
#. module: auto_backup
|
||||||
#: code:addons/auto_backup/models/db_backup.py:128
|
#: code:addons/auto_backup/models/db_backup.py:137
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Connection Test Failed!"
|
msgid "Connection Test Failed!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: auto_backup
|
#. module: auto_backup
|
||||||
#: code:addons/auto_backup/models/db_backup.py:123
|
#: code:addons/auto_backup/models/db_backup.py:132
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Connection Test Succeeded!"
|
msgid "Connection Test Succeeded!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -105,14 +115,14 @@ msgid "Database Backup"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: auto_backup
|
#. module: auto_backup
|
||||||
#: code:addons/auto_backup/models/db_backup.py:203
|
#: code:addons/auto_backup/models/db_backup.py:219
|
||||||
#: model:mail.message.subtype,description:auto_backup.mail_message_subtype_failure
|
#: model:mail.message.subtype,description:auto_backup.mail_message_subtype_failure
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Database backup failed."
|
msgid "Database backup failed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: auto_backup
|
#. module: auto_backup
|
||||||
#: code:addons/auto_backup/models/db_backup.py:211
|
#: code:addons/auto_backup/models/db_backup.py:227
|
||||||
#: model:mail.message.subtype,description:auto_backup.mail_message_subtype_success
|
#: model:mail.message.subtype,description:auto_backup.mail_message_subtype_success
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Database backup succeeded."
|
msgid "Database backup succeeded."
|
||||||
|
@ -129,7 +139,7 @@ msgid "Display Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: auto_backup
|
#. module: auto_backup
|
||||||
#: code:addons/auto_backup/models/db_backup.py:114
|
#: code:addons/auto_backup/models/db_backup.py:123
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Do not save backups on your filestore, or you will backup your backups too!"
|
msgid "Do not save backups on your filestore, or you will backup your backups too!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -294,8 +304,18 @@ msgstr ""
|
||||||
msgid "john"
|
msgid "john"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: auto_backup
|
||||||
|
#: selection:db.backup,backup_format:0
|
||||||
|
msgid "pg_dump custom format (without filestore)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: auto_backup
|
#. module: auto_backup
|
||||||
#: model:ir.ui.view,arch_db:auto_backup.view_backup_conf_form
|
#: model:ir.ui.view,arch_db:auto_backup.view_backup_conf_form
|
||||||
msgid "sftp.example.com"
|
msgid "sftp.example.com"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: auto_backup
|
||||||
|
#: selection:db.backup,backup_format:0
|
||||||
|
msgid "zip (includes filestore)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,15 @@ class DbBackup(models.Model):
|
||||||
"read permissions for that file.",
|
"read permissions for that file.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
backup_format = fields.Selection(
|
||||||
|
[
|
||||||
|
("zip", "zip (includes filestore)"),
|
||||||
|
("dump", "pg_dump custom format (without filestore)")
|
||||||
|
],
|
||||||
|
default='zip',
|
||||||
|
help="Choose the format for this backup."
|
||||||
|
)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _default_folder(self):
|
def _default_folder(self):
|
||||||
"""Default to ``backups`` folder inside current server datadir."""
|
"""Default to ``backups`` folder inside current server datadir."""
|
||||||
|
@ -131,11 +140,11 @@ class DbBackup(models.Model):
|
||||||
def action_backup(self):
|
def action_backup(self):
|
||||||
"""Run selected backups."""
|
"""Run selected backups."""
|
||||||
backup = None
|
backup = None
|
||||||
filename = self.filename(datetime.now())
|
|
||||||
successful = self.browse()
|
successful = self.browse()
|
||||||
|
|
||||||
# Start with local storage
|
# Start with local storage
|
||||||
for rec in self.filtered(lambda r: r.method == "local"):
|
for rec in self.filtered(lambda r: r.method == "local"):
|
||||||
|
filename = self.filename(datetime.now(), ext=rec.backup_format)
|
||||||
with rec.backup_log():
|
with rec.backup_log():
|
||||||
# Directory must exist
|
# Directory must exist
|
||||||
try:
|
try:
|
||||||
|
@ -151,21 +160,28 @@ class DbBackup(models.Model):
|
||||||
shutil.copyfileobj(cached, destiny)
|
shutil.copyfileobj(cached, destiny)
|
||||||
# Generate new backup
|
# Generate new backup
|
||||||
else:
|
else:
|
||||||
db.dump_db(self.env.cr.dbname, destiny)
|
db.dump_db(
|
||||||
|
self.env.cr.dbname,
|
||||||
|
destiny,
|
||||||
|
backup_format=rec.backup_format
|
||||||
|
)
|
||||||
backup = backup or destiny.name
|
backup = backup or destiny.name
|
||||||
successful |= rec
|
successful |= rec
|
||||||
|
|
||||||
# Ensure a local backup exists if we are going to write it remotely
|
# Ensure a local backup exists if we are going to write it remotely
|
||||||
sftp = self.filtered(lambda r: r.method == "sftp")
|
sftp = self.filtered(lambda r: r.method == "sftp")
|
||||||
if sftp:
|
if sftp:
|
||||||
if backup:
|
for rec in sftp:
|
||||||
cached = open(backup)
|
filename = self.filename(datetime.now(), ext=rec.backup_format)
|
||||||
else:
|
with rec.backup_log():
|
||||||
cached = db.dump_db(self.env.cr.dbname, None)
|
|
||||||
|
|
||||||
with cached:
|
cached = db.dump_db(
|
||||||
for rec in sftp:
|
self.env.cr.dbname,
|
||||||
with rec.backup_log():
|
None,
|
||||||
|
backup_format=rec.backup_format
|
||||||
|
)
|
||||||
|
|
||||||
|
with cached:
|
||||||
with rec.sftp_connection() as remote:
|
with rec.sftp_connection() as remote:
|
||||||
# Directory must exist
|
# Directory must exist
|
||||||
try:
|
try:
|
||||||
|
@ -255,13 +271,16 @@ class DbBackup(models.Model):
|
||||||
self.name)
|
self.name)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filename(when):
|
def filename(when, ext='zip'):
|
||||||
"""Generate a file name for a backup.
|
"""Generate a file name for a backup.
|
||||||
|
|
||||||
:param datetime.datetime when:
|
:param datetime.datetime when:
|
||||||
Use this datetime instead of :meth:`datetime.datetime.now`.
|
Use this datetime instead of :meth:`datetime.datetime.now`.
|
||||||
|
:param str ext: Extension of the file. Default: dump.zip
|
||||||
"""
|
"""
|
||||||
return "{:%Y_%m_%d_%H_%M_%S}.dump.zip".format(when)
|
return "{:%Y_%m_%d_%H_%M_%S}.{ext}".format(
|
||||||
|
when, ext='dump.zip' if ext == 'zip' else ext
|
||||||
|
)
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def sftp_connection(self):
|
def sftp_connection(self):
|
||||||
|
|
|
@ -175,18 +175,6 @@ class TestDbBackup(common.TransactionCase):
|
||||||
'wb'
|
'wb'
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_action_backup_sftp_remote_open(self):
|
|
||||||
""" It should open remote file w/ proper args """
|
|
||||||
rec_id = self.new_record()
|
|
||||||
with self.mock_assets() as assets:
|
|
||||||
with self.patch_filtered_sftp(rec_id):
|
|
||||||
conn = rec_id.sftp_connection().__enter__()
|
|
||||||
rec_id.action_backup()
|
|
||||||
conn.open.assert_called_once_with(
|
|
||||||
assets['os'].path.join(),
|
|
||||||
'wb'
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_action_backup_all_search(self):
|
def test_action_backup_all_search(self):
|
||||||
""" It should search all records """
|
""" It should search all records """
|
||||||
rec_id = self.new_record()
|
rec_id = self.new_record()
|
||||||
|
@ -241,8 +229,20 @@ class TestDbBackup(common.TransactionCase):
|
||||||
pysftp.Connection(), res,
|
pysftp.Connection(), res,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_filename(self):
|
def test_filename_default(self):
|
||||||
""" It should not error and should return a .dump.zip file str """
|
""" It should not error and should return a .dump.zip file str """
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
res = self.Model.filename(now)
|
res = self.Model.filename(now)
|
||||||
self.assertTrue(res.endswith(".dump.zip"))
|
self.assertTrue(res.endswith(".dump.zip"))
|
||||||
|
|
||||||
|
def test_filename_zip(self):
|
||||||
|
""" It should return a dump.zip filename"""
|
||||||
|
now = datetime.now()
|
||||||
|
res = self.Model.filename(now, ext='zip')
|
||||||
|
self.assertTrue(res.endswith(".dump.zip"))
|
||||||
|
|
||||||
|
def test_filename_dump(self):
|
||||||
|
""" It should return a dump filename"""
|
||||||
|
now = datetime.now()
|
||||||
|
res = self.Model.filename(now, ext='dump')
|
||||||
|
self.assertTrue(res.endswith(".dump"))
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
<field name="folder"/>
|
<field name="folder"/>
|
||||||
<field name="days_to_keep"/>
|
<field name="days_to_keep"/>
|
||||||
<field name="method"/>
|
<field name="method"/>
|
||||||
|
<field name="backup_format"/>
|
||||||
</group>
|
</group>
|
||||||
<div attrs="{'invisible': [('method', '!=', 'sftp')]}">
|
<div attrs="{'invisible': [('method', '!=', 'sftp')]}">
|
||||||
<div class="bg-warning text-warning">
|
<div class="bg-warning text-warning">
|
||||||
|
|
Loading…
Reference in New Issue