Introduce mariadb_backup backup_strategy

With mariabackup being renamed to mariadb-backup binary, to keep
some backwards compatability instead of renaming the binary
to call, this patch introduces the whole new strategy designed to
pretty much override only used binary name for modern MariaDB
versions.

This new strategy is selected whenever requested datastore version
is equal or higher 10.4.

This patch is alternative to [1]

[1] https://review.opendev.org/c/openstack/trove/+/948643

Change-Id: I5336c8f98d9f1f33810113b9d7a84f1bef3deb66
This commit is contained in:
Dmitriy Rabotyagov
2025-05-15 18:27:41 +02:00
parent 3e0b163d80
commit bcdec128e4
4 changed files with 139 additions and 9 deletions

View File

@@ -25,17 +25,19 @@ CONF = cfg.CONF
class MariaBackup(mysql_base.MySQLBaseRunner):
"""Implementation of Backup and Restore using mariabackup."""
backup_binary = 'mariabackup'
restore_cmd = ('mbstream -x -C %(restore_location)s')
prepare_cmd = 'mariabackup --prepare --target-dir=%(restore_location)s'
prepare_cmd = \
f'{backup_binary} --prepare --target-dir=%(restore_location)s'
def __init__(self, *args, **kwargs):
super(MariaBackup, self).__init__(*args, **kwargs)
self.backup_log = '/tmp/mariabackup.log'
self.backup_log = f'/tmp/{self.backup_binary}.log'
self._gzip = True
@property
def cmd(self):
cmd = ('mariabackup --backup --stream=xbstream ' +
cmd = (f'{self.backup_binary} --backup --stream=xbstream ' +
self.user_and_pass)
return cmd
@@ -64,9 +66,15 @@ class MariaBackup(mysql_base.MySQLBaseRunner):
raise Exception(msg)
class MariaDBBackup(MariaBackup):
"""Implementation of Backup and Restore using mariadb-backup."""
backup_binary = 'mariadb-backup'
class MariaBackupIncremental(MariaBackup):
"""Incremental backup and restore using mariabackup."""
incremental_prep = ('mariabackup --prepare '
incremental_prep_binary = MariaBackup.backup_binary
incremental_prep = (f'{incremental_prep_binary} --prepare '
'--target-dir=%(restore_location)s '
'%(incremental_args)s')
@@ -81,7 +89,7 @@ class MariaBackupIncremental(MariaBackup):
@property
def cmd(self):
cmd = (
'mariabackup --backup --stream=xbstream'
f'{self.incremental_prep_binary} --backup --stream=xbstream'
' --incremental-lsn=%(lsn)s ' +
self.user_and_pass
)
@@ -102,3 +110,8 @@ class MariaBackupIncremental(MariaBackup):
LOG.info('Running incremental restore')
self.incremental_restore(self.location, self.checksum)
return self.restore_content_length
class MariaDBBackupIncremental(MariaBackupIncremental):
"""Incremental backup and restore using mariadb-backup."""
incremental_prep_binary = MariaDBBackup.backup_binary

View File

@@ -19,6 +19,7 @@ import sys
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import importutils
from semantic_version import Version
topdir = os.path.normpath(
os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))
@@ -37,7 +38,13 @@ cli_opts = [
cfg.StrOpt(
'driver',
default='innobackupex',
choices=['innobackupex', 'mariabackup', 'pg_basebackup', 'xtrabackup']
choices=[
'innobackupex',
'mariabackup',
'mariadb_backup',
'pg_basebackup',
'xtrabackup'
]
),
cfg.BoolOpt('backup'),
cfg.StrOpt(
@@ -72,7 +79,10 @@ driver_mapping = {
'innobackupex': 'backup.drivers.innobackupex.InnoBackupEx',
'innobackupex_inc': 'backup.drivers.innobackupex.InnoBackupExIncremental',
'mariabackup': 'backup.drivers.mariabackup.MariaBackup',
'mariadb_backup': 'backup.drivers.mariabackup.MariaDBBackup',
'mariabackup_inc': 'backup.drivers.mariabackup.MariaBackupIncremental',
'mariadb_backup_inc':
'backup.drivers.mariabackup.MariaDBBackupIncremental',
'pg_basebackup': 'backup.drivers.postgres.PgBasebackup',
'pg_basebackup_inc': 'backup.drivers.postgres.PgBasebackupIncremental',
'xtrabackup': 'backup.drivers.xtrabackup.XtraBackup',
@@ -148,13 +158,19 @@ def main():
CONF(sys.argv[1:], project='trove-backup')
logging.setup(CONF, 'trove-backup')
runner_cls = importutils.import_class(driver_mapping[CONF.driver])
driver = CONF.driver
if driver == "mariabackup":
ds_version = CONF.swift_extra_metadata.get('datastore_version', '0.0')
if Version.coerce(ds_version) >= Version.coerce("10.4"):
driver = "mariadb_backup"
runner_cls = importutils.import_class(driver_mapping[driver])
storage = importutils.import_class(storage_mapping[CONF.storage_driver])()
if CONF.backup:
if CONF.incremental:
runner_cls = importutils.import_class(
driver_mapping['%s_inc' % CONF.driver])
driver_mapping['%s_inc' % driver])
LOG.info('Starting backup database to %s, backup ID %s',
CONF.storage_driver, CONF.backup_id)
@@ -163,7 +179,7 @@ def main():
if storage.is_incremental_backup(CONF.restore_from):
LOG.debug('Restore from incremental backup')
runner_cls = importutils.import_class(
driver_mapping['%s_inc' % CONF.driver])
driver_mapping['%s_inc' % driver])
LOG.info('Starting restore database from %s, location: %s',
CONF.storage_driver, CONF.restore_from)

View File

@@ -31,7 +31,10 @@ driver_mapping = {
'innobackupex': 'backup.drivers.innobackupex.InnoBackupEx',
'innobackupex_inc': 'backup.drivers.innobackupex.InnoBackupExIncremental',
'mariabackup': 'backup.drivers.mariabackup.MariaBackup',
'mariadb_backup': 'backup.drivers.mariabackup.MariaDBBackup',
'mariabackup_inc': 'backup.drivers.mariabackup.MariaBackupIncremental',
'mariadb_backup_inc':
'backup.drivers.mariabackup.MariaDBBackupIncremental',
'pg_basebackup': 'backup.drivers.postgres.PgBasebackup',
'pg_basebackup_inc': 'backup.drivers.postgres.PgBasebackupIncremental',
'xtrabackup': 'backup.drivers.xtrabackup.XtraBackup',
@@ -80,6 +83,47 @@ class TestMariaBackup(unittest.TestCase):
self.assertEqual(runner.check_restore_process(), True)
class TestMariaDBBackup(unittest.TestCase):
def setUp(self):
self.runner_cls = importutils.import_class(
driver_mapping['mariadb_backup'])
self.params = {}
# assertions
self.assertIsNotNone(self.runner_cls)
def tearDown(self):
pass
def test_instance(self):
'''Check instance'''
# call the method
runner = self.runner_cls(**self.params)
# assertions
self.assertIsNotNone(runner)
def test_cmd(self):
'''Check cmd property'''
# call the method
runner = self.runner_cls(**self.params)
# assertions
cmd = ("mariadb-backup --backup --stream=xbstream {}".format(
runner.user_and_pass))
self.assertEqual(runner.cmd, cmd)
def test_check_restore_process(self):
'''Check manifest'''
runner = self.runner_cls(**self.params)
runner.process = MagicMock()
returncode = PropertyMock(return_value=0)
type(runner.process).returncode = returncode
# call the method
self.assertEqual(runner.check_restore_process(), True)
class TestMariaBackupIncremental(unittest.TestCase):
def setUp(self):
self.runner_cls = importutils.import_class(
@@ -131,5 +175,56 @@ class TestMariaBackupIncremental(unittest.TestCase):
self.assertEqual(ret, length)
class TestMariaDBBackupIncremental(unittest.TestCase):
def setUp(self):
self.runner_cls = importutils.import_class(
driver_mapping['mariadb_backup_inc'])
self.params = {
'lsn': '1234567890',
'incremental_dir': './'
}
self.metadata = {}
def tearDown(self):
pass
def test_cmd(self):
'''Check cmd property'''
# call the method
runner = self.runner_cls(**self.params)
# assertions
cmd = (
'mariadb-backup --backup --stream=xbstream'
' --incremental-lsn=%(lsn)s ' +
runner.user_and_pass
)
self.assertEqual(runner.cmd, cmd)
def test_get_metadata(self):
# prepare the test
runner = self.runner_cls(**self.params)
runner.get_metadata = MagicMock(return_value=self.metadata)
# call the method
ret = runner.get_metadata()
# assertions
self.assertEqual(ret, self.metadata)
def test_run_restore(self):
# prepare the test
runner = self.runner_cls(**self.params)
length = 10
runner.incremental_restore = MagicMock(return_value=length)
runner.restore_content_length = length
# call the method
ret = runner.run_restore()
# assertions
self.assertEqual(ret, length)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,6 @@
---
fixes:
- |
For MariaDB datastore of versions equal or higher then 10.4,
`mariadb-backup` binary will be executed instead of `mariabackup`
when performing backup or restore process.