Move mysql datadir to a sub-directory on mounted volume

Having the mysql datadir located at root of a mounted volume
(which happens with volume support enabled) causes problems for
backup/restore and resize. Mysql decides that the "lost+found"
directory, which the operating system puts at the root of each
file system, is actually a mysql "database".

This change causes the guest agent to move the datadir into a
sub-directory called "data" on the mounted volume.

Change-Id: Ica628012a5708374d73e5394e370da2514300939
Co-Authored-By: Simon Chang <schang@tesora.com>
Closes-bug: 1370646
This commit is contained in:
Doug Shelley 2015-01-16 16:22:37 +00:00 committed by Simon Chang
parent a41fe2c2d5
commit ad42de03d3
24 changed files with 116 additions and 59 deletions

View File

@ -1,5 +1,5 @@
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1077
Content-Length: 1082
Date: Mon, 18 Mar 2013 19:09:17 GMT

View File

@ -3,7 +3,7 @@
"configuration": {
"basedir": "/usr",
"connect_timeout": "15",
"datadir": "/var/lib/mysql",
"datadir": "/var/lib/mysql/data",
"default_storage_engine": "innodb",
"innodb_buffer_pool_size": "150M",
"innodb_data_file_path": "ibdata1:10M:autoextend",

View File

@ -23,6 +23,7 @@ from trove.common import exception
from trove.common.i18n import _
from trove.common import instance as rd_instance
from trove.guestagent import backup
from trove.guestagent.common import operating_system
from trove.guestagent.datastore.mysql.service import MySqlAdmin
from trove.guestagent.datastore.mysql.service import MySqlApp
from trove.guestagent.datastore.mysql.service import MySqlAppStatus
@ -130,15 +131,24 @@ class Manager(periodic_task.PeriodicTasks):
device.unmount_device(device_path)
device.format()
if os.path.exists(mount_point):
# rsync exiting data
device.migrate_data(mount_point)
# rsync existing data to a "data" sub-directory
# on the new volume
device.migrate_data(mount_point, target_subdir="data")
# mount the volume
device.mount(mount_point)
LOG.debug("Mounted the volume.")
operating_system.chown(mount_point, 'mysql', 'mysql',
recursive=False, as_root=True)
LOG.debug("Mounted the volume at %s." % mount_point)
# We need to temporarily update the default my.cnf so that
# mysql will start after the volume is mounted. Later on it
# will be changed based on the config template and restart.
app.update_overrides("[mysqld]\ndatadir=%s/data\n"
% mount_point)
app.start_mysql()
if backup_info:
self._perform_restore(backup_info, context,
mount_point, app)
mount_point + "/data", app)
LOG.debug("Securing MySQL now.")
app.secure(config_contents, overrides)
enable_root_on_restore = (backup_info and

View File

@ -27,6 +27,7 @@ from sqlalchemy import interfaces
from sqlalchemy.sql.expression import text
from trove.common import cfg
from trove.common import configurations
from trove.common import exception
from trove.common.exception import PollTimeOut
from trove.common.i18n import _
@ -44,11 +45,11 @@ ADMIN_USER_NAME = "os_admin"
LOG = logging.getLogger(__name__)
FLUSH = text(sql_query.FLUSH)
ENGINE = None
DATADIR = None
PREPARING = False
UUID = False
TMP_MYCNF = "/tmp/my.cnf.tmp"
MYSQL_BASE_DIR = "/var/lib/mysql"
CONF = cfg.CONF
MANAGER = CONF.datastore_manager if CONF.datastore_manager else 'mysql'
@ -156,6 +157,28 @@ def load_mysqld_options():
return {}
def read_mycnf():
with open(MYSQL_CONFIG, 'r') as file:
config_contents = file.read()
return config_contents
def get_datadir(reset_cache=False):
"""Return the data directory currently used by Mysql."""
global DATADIR
if not reset_cache and DATADIR:
return DATADIR
mycnf_contents = read_mycnf()
# look for datadir parameter in my.cnf
mycnf = dict(configurations.MySQLConfParser(mycnf_contents).parse())
DATADIR = mycnf['datadir']
return DATADIR
class MySqlAppStatus(service.BaseDbStatus):
@classmethod
def get(cls):
@ -427,10 +450,6 @@ class MySqlAdmin(object):
"be omitted from the listing: %s" % ignored_database_names)
databases = []
with LocalSqlClient(get_engine()) as client:
# If you have an external volume mounted at /var/lib/mysql
# the lost+found directory will show up in mysql as a database
# which will create errors if you try to do any database ops
# on it. So we remove it here if it exists.
q = sql_query.Query()
q.columns = [
'schema_name as name',
@ -769,7 +788,7 @@ class MySqlApp(object):
# to be deleted. That's why its ok if they aren't found and
# that is why we use the "force" option to "remove".
operating_system.remove("%s/ib_logfile%d"
% (MYSQL_BASE_DIR, index), force=True,
% (get_datadir(), index), force=True,
as_root=True)
except exception.ProcessExecutionError:
LOG.exception("Could not delete logfile.")

View File

@ -19,6 +19,7 @@ import re
from trove.guestagent.datastore.mysql.service import ADMIN_USER_NAME
from trove.guestagent.datastore.mysql.service import get_auth_password
from trove.guestagent.datastore.mysql.service import get_datadir
from trove.guestagent.strategies.backup import base
from trove.openstack.common import log as logging
@ -51,8 +52,9 @@ class InnoBackupEx(base.BackupRunner):
def cmd(self):
cmd = ('sudo innobackupex'
' --stream=xbstream'
' %(extra_opts)s'
' /var/lib/mysql 2>/tmp/innobackupex.log'
' %(extra_opts)s '
+ get_datadir() +
' 2>/tmp/innobackupex.log'
)
return cmd + self.zip_cmd + self.encrypt_cmd
@ -105,8 +107,8 @@ class InnoBackupExIncremental(InnoBackupEx):
' --stream=xbstream'
' --incremental'
' --incremental-lsn=%(lsn)s'
' %(extra_opts)s'
' /var/lib/mysql'
' %(extra_opts)s '
+ get_datadir() +
' 2>/tmp/innobackupex.log')
return cmd + self.zip_cmd + self.encrypt_cmd

View File

@ -22,6 +22,7 @@ from trove.common.i18n import _
from trove.guestagent.backup.backupagent import BackupAgent
from trove.guestagent.common import operating_system
from trove.guestagent.common.operating_system import FileMode
from trove.guestagent.datastore.mysql.service import get_datadir
from trove.guestagent.strategies.replication import mysql_base
from trove.openstack.common import log as logging
@ -61,7 +62,7 @@ class MysqlBinlogReplication(mysql_base.MysqlReplicationBase):
service.start_slave()
def _read_log_position(self):
INFO_FILE = '/var/lib/mysql/data/xtrabackup_binlog_info'
INFO_FILE = ('%s/xtrabackup_binlog_info' % get_datadir())
LOG.info(_("Setting read permissions on %s") % INFO_FILE)
operating_system.chmod(INFO_FILE, FileMode.ADD_READ_ALL, as_root=True)
LOG.info(_("Reading log position from %s") % INFO_FILE)

View File

@ -54,8 +54,7 @@ class RestoreRunner(Strategy):
self.storage = storage
self.location = kwargs.pop('location')
self.checksum = kwargs.pop('checksum')
self.restore_location = kwargs.get('restore_location',
'/var/lib/mysql')
self.restore_location = kwargs.get('restore_location')
self.restore_cmd = (self.decrypt_cmd +
self.unzip_cmd +
(self.base_restore_cmd % kwargs))

View File

@ -293,7 +293,7 @@ class InnoBackupExIncremental(InnoBackupEx):
self._incremental_restore(parent_location, parent_checksum)
# for *this* backup set the incremental_dir
# just use the checksum for the incremental path as it is
# sufficiently unique /var/lib/mysql/<checksum>
# sufficiently unique /var/lib/mysql/data/<checksum>
incremental_dir = os.path.join(self.restore_location, checksum)
operating_system.create_directory(incremental_dir, as_root=True)
command = self._incremental_restore_cmd(incremental_dir)

View File

@ -37,16 +37,19 @@ class VolumeDevice(object):
def __init__(self, device_path):
self.device_path = device_path
def migrate_data(self, source_dir):
def migrate_data(self, source_dir, target_subdir=None):
"""Synchronize the data from the source directory to the new
volume.
volume; optionally to a new sub-directory on the new volume.
"""
self.mount(TMP_MOUNT_POINT, write_to_fstab=False)
if not source_dir[-1] == '/':
source_dir = "%s/" % source_dir
target_dir = TMP_MOUNT_POINT
if target_subdir:
target_dir = target_dir + "/" + target_subdir
utils.execute("sudo", "rsync", "--safe-links", "--perms",
"--recursive", "--owner", "--group", "--xattrs",
"--sparse", source_dir, TMP_MOUNT_POINT)
"--sparse", source_dir, target_dir)
self.unmount(TMP_MOUNT_POINT)
def _check_device_exists(self):

View File

@ -1,4 +1,4 @@
[mysqld]
log_bin = /var/lib/mysql/mysql-bin.log
relay_log = /var/lib/mysql/mysql-relay-bin.log
log_bin = /var/lib/mysql/data/mysql-bin.log
relay_log = /var/lib/mysql/data/mysql-relay-bin.log
read_only = true

View File

@ -1,2 +1,2 @@
[mysqld]
log_bin = /var/lib/mysql/mysql-bin.log
log_bin = /var/lib/mysql/data/mysql-bin.log

View File

@ -8,7 +8,7 @@ nice = 0
user = mysql
port = 3306
basedir = /usr
datadir = /var/lib/mysql
datadir = /var/lib/mysql/data
####tmpdir = /tmp
tmpdir = /var/tmp
pid_file = /var/run/mysqld/mysqld.pid

View File

@ -1,6 +1,6 @@
[mysqld]
log_bin = /var/lib/mysql/mysql-bin.log
relay_log = /var/lib/mysql/mysql-relay-bin.log
log_bin = /var/lib/mysql/data/mysql-bin.log
relay_log = /var/lib/mysql/data/mysql-relay-bin.log
relay_log_info_repository = TABLE
relay_log_recovery = 1
relay_log_purge = 1

View File

@ -1,5 +1,5 @@
[mysqld]
log_bin = /var/lib/mysql/mysql-bin.log
log_bin = /var/lib/mysql/data/mysql-bin.log
binlog_format = MIXED
enforce_gtid_consistency = ON
gtid_mode = ON

View File

@ -1,4 +1,4 @@
[mysqld]
log_bin = /var/lib/mysql/mysql-bin.log
relay_log = /var/lib/mysql/mysql-relay-bin.log
log_bin = /var/lib/mysql/data/mysql-bin.log
relay_log = /var/lib/mysql/data/mysql-relay-bin.log
read_only = true

View File

@ -1,2 +1,2 @@
[mysqld]
log_bin = /var/lib/mysql/mysql-bin.log
log_bin = /var/lib/mysql/data/mysql-bin.log

View File

@ -8,7 +8,7 @@ nice = 0
user = mysql
port = 3306
basedir = /usr
datadir = /var/lib/mysql
datadir = /var/lib/mysql/data
####tmpdir = /tmp
tmpdir = /var/tmp
pid_file = /var/run/mysqld/mysqld.pid

View File

@ -1,6 +1,6 @@
[mysqld]
log_bin = /var/lib/mysql/mysql-bin.log
relay_log = /var/lib/mysql/mysql-relay-bin.log
log_bin = /var/lib/mysql/data/mysql-bin.log
relay_log = /var/lib/mysql/data/mysql-relay-bin.log
relay_log_info_repository = TABLE
relay_log_recovery = 1
relay_log_purge = 1

View File

@ -1,5 +1,5 @@
[mysqld]
log_bin = /var/lib/mysql/mysql-bin.log
log_bin = /var/lib/mysql/data/mysql-bin.log
binlog_format = MIXED
enforce_gtid_consistency = ON
gtid_mode = ON

View File

@ -235,7 +235,7 @@ class RebootTestBase(ActionTestBase):
def mess_up_mysql(self):
"""Ruin MySQL's ability to restart."""
server = create_server_connection(self.instance_id)
cmd = "sudo cp /dev/null /var/lib/mysql/ib_logfile%d"
cmd = "sudo cp /dev/null /var/lib/mysql/data/ib_logfile%d"
instance_info.dbaas_admin.management.stop(self.instance_id)
for index in range(2):
server.execute(cmd % index)
@ -244,7 +244,7 @@ class RebootTestBase(ActionTestBase):
"""Fix MySQL's ability to restart."""
if not FAKE_MODE:
server = create_server_connection(self.instance_id)
cmd = "sudo rm /var/lib/mysql/ib_logfile%d"
cmd = "sudo rm /var/lib/mysql/data/ib_logfile%d"
# We want to stop mysql so that upstart does not keep trying to
# respawn it and block the guest agent from accessing the logs.
instance_info.dbaas_admin.management.stop(self.instance_id)

View File

@ -13,6 +13,7 @@
# limitations under the License.
import hashlib
import mock
import os
from mock import Mock, MagicMock, patch, ANY
@ -203,16 +204,18 @@ class BackupAgentTest(trove_testtools.TestCase):
self.assertIsNotNone(mysql_dump.manifest)
self.assertEqual('abc.gz.enc', mysql_dump.manifest)
def test_backup_impl_InnoBackupEx(self):
@mock.patch('trove.guestagent.strategies.backup.mysql_impl.get_datadir')
def test_backup_impl_InnoBackupEx(self, mock_datadir):
"""This test is for
guestagent/strategies/backup/impl
"""
mock_datadir.return_value = '/var/lib/mysql/data'
inno_backup_ex = mysql_impl.InnoBackupEx('innobackupex', extra_opts='')
self.assertIsNotNone(inno_backup_ex.cmd)
str_innobackup_cmd = ('sudo innobackupex'
' --stream=xbstream'
' %(extra_opts)s'
' /var/lib/mysql 2>/tmp/innobackupex.log'
' /var/lib/mysql/data 2>/tmp/innobackupex.log'
' | gzip |'
' openssl enc -aes-256-cbc -salt '
'-pass pass:default_aes_cbc_key')
@ -394,7 +397,7 @@ class BackupAgentTest(trove_testtools.TestCase):
}
agent.execute_restore(TroveContext(),
bkup_info,
'/var/lib/mysql')
'/var/lib/mysql/data')
def test_restore_unknown(self):
with patch.object(backupagent, 'get_restore_strategy',
@ -410,7 +413,7 @@ class BackupAgentTest(trove_testtools.TestCase):
self.assertRaises(UnknownBackupType, agent.execute_restore,
context=None, backup_info=bkup_info,
restore_location='/var/lib/mysql')
restore_location='/var/lib/mysql/data')
@patch.object(conductor_api.API, 'get_client', Mock(return_value=Mock()))
@patch.object(MockSwift, 'load_metadata', return_value={'lsn': '54321'})
@ -440,7 +443,7 @@ class BackupAgentTest(trove_testtools.TestCase):
agent.execute_backup(TroveContext(),
bkup_info,
'/var/lib/mysql')
'/var/lib/mysql/data')
self.assertTrue(MockStorage.save_metadata.called_once_with(
ANY,

View File

@ -50,12 +50,13 @@ UNZIP = "gzip -d -c"
ENCRYPT = "openssl enc -aes-256-cbc -salt -pass pass:default_aes_cbc_key"
DECRYPT = "openssl enc -d -aes-256-cbc -salt -pass pass:default_aes_cbc_key"
XTRA_BACKUP_RAW = ("sudo innobackupex --stream=xbstream %(extra_opts)s"
" /var/lib/mysql 2>/tmp/innobackupex.log")
" /var/lib/mysql/data 2>/tmp/innobackupex.log")
XTRA_BACKUP = XTRA_BACKUP_RAW % {'extra_opts': ''}
XTRA_BACKUP_EXTRA_OPTS = XTRA_BACKUP_RAW % {'extra_opts': '--no-lock'}
XTRA_BACKUP_INCR = ('sudo innobackupex --stream=xbstream'
' --incremental --incremental-lsn=%(lsn)s'
' %(extra_opts)s /var/lib/mysql 2>/tmp/innobackupex.log')
' %(extra_opts)s /var/lib/mysql/data'
' 2>/tmp/innobackupex.log')
SQLDUMP_BACKUP_RAW = ("mysqldump --all-databases %(extra_opts)s "
"--opt --password=password -u os_admin"
" 2>/tmp/mysqldump.log")
@ -63,15 +64,15 @@ SQLDUMP_BACKUP = SQLDUMP_BACKUP_RAW % {'extra_opts': ''}
SQLDUMP_BACKUP_EXTRA_OPTS = (SQLDUMP_BACKUP_RAW %
{'extra_opts': '--events --routines --triggers'})
XTRA_RESTORE_RAW = "sudo xbstream -x -C %(restore_location)s"
XTRA_RESTORE = XTRA_RESTORE_RAW % {'restore_location': '/var/lib/mysql'}
XTRA_RESTORE = XTRA_RESTORE_RAW % {'restore_location': '/var/lib/mysql/data'}
XTRA_INCR_PREPARE = ("sudo innobackupex --apply-log"
" --redo-only /var/lib/mysql"
" --defaults-file=/var/lib/mysql/backup-my.cnf"
" --redo-only /var/lib/mysql/data"
" --defaults-file=/var/lib/mysql/data/backup-my.cnf"
" --ibbackup xtrabackup %(incr)s"
" 2>/tmp/innoprepare.log")
SQLDUMP_RESTORE = "sudo mysql"
PREPARE = ("sudo innobackupex --apply-log /var/lib/mysql "
"--defaults-file=/var/lib/mysql/backup-my.cnf "
PREPARE = ("sudo innobackupex --apply-log /var/lib/mysql/data "
"--defaults-file=/var/lib/mysql/data/backup-my.cnf "
"--ibbackup xtrabackup 2>/tmp/innoprepare.log")
CRYPTO_KEY = "default_aes_cbc_key"
@ -92,11 +93,16 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
mysql_impl.get_auth_password = mock.Mock(
return_value='password')
self.orig_exec_with_to = utils.execute_with_timeout
self.patcher_get_datadir = patch(
'trove.guestagent.strategies.backup.mysql_impl.get_datadir')
self.mock_get_datadir = self.patcher_get_datadir.start()
self.mock_get_datadir.return_value = '/var/lib/mysql/data'
def tearDown(self):
super(GuestAgentBackupTest, self).tearDown()
mysql_impl.get_auth_password = self.orig
utils.execute_with_timeout = self.orig_exec_with_to
self.patcher_get_datadir.stop()
def test_backup_decrypted_xtrabackup_command(self):
backupBase.BackupRunner.is_zipped = True
@ -186,7 +192,7 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
restoreBase.RestoreRunner.is_zipped = True
restoreBase.RestoreRunner.is_encrypted = False
RunnerClass = utils.import_class(RESTORE_XTRA_CLS)
restr = RunnerClass(None, restore_location="/var/lib/mysql",
restr = RunnerClass(None, restore_location="/var/lib/mysql/data",
location="filename", checksum="md5")
self.assertEqual(UNZIP + PIPE + XTRA_RESTORE, restr.restore_cmd)
self.assertEqual(PREPARE, restr.prepare_cmd)
@ -196,7 +202,7 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
restoreBase.RestoreRunner.is_encrypted = True
restoreBase.RestoreRunner.decrypt_key = CRYPTO_KEY
RunnerClass = utils.import_class(RESTORE_XTRA_CLS)
restr = RunnerClass(None, restore_location="/var/lib/mysql",
restr = RunnerClass(None, restore_location="/var/lib/mysql/data",
location="filename", checksum="md5")
self.assertEqual(DECRYPT + PIPE + UNZIP + PIPE + XTRA_RESTORE,
restr.restore_cmd)
@ -204,7 +210,7 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
def test_restore_xtrabackup_incremental_prepare_command(self):
RunnerClass = utils.import_class(RESTORE_XTRA_INCR_CLS)
restr = RunnerClass(None, restore_location="/var/lib/mysql",
restr = RunnerClass(None, restore_location="/var/lib/mysql/data",
location="filename", checksum="m5d")
# Final prepare command (same as normal xtrabackup)
self.assertEqual(PREPARE, restr.prepare_cmd)
@ -221,7 +227,7 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
restoreBase.RestoreRunner.is_zipped = True
restoreBase.RestoreRunner.is_encrypted = False
RunnerClass = utils.import_class(RESTORE_XTRA_INCR_CLS)
restr = RunnerClass(None, restore_location="/var/lib/mysql",
restr = RunnerClass(None, restore_location="/var/lib/mysql/data",
location="filename", checksum="m5d")
# Full restore command
expected = UNZIP + PIPE + XTRA_RESTORE
@ -237,7 +243,7 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
restoreBase.RestoreRunner.is_encrypted = True
restoreBase.RestoreRunner.decrypt_key = CRYPTO_KEY
RunnerClass = utils.import_class(RESTORE_XTRA_INCR_CLS)
restr = RunnerClass(None, restore_location="/var/lib/mysql",
restr = RunnerClass(None, restore_location="/var/lib/mysql/data",
location="filename", checksum="md5")
# Full restore command
expected = DECRYPT + PIPE + UNZIP + PIPE + XTRA_RESTORE
@ -252,7 +258,7 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
restoreBase.RestoreRunner.is_zipped = True
restoreBase.RestoreRunner.is_encrypted = False
RunnerClass = utils.import_class(RESTORE_SQLDUMP_CLS)
restr = RunnerClass(None, restore_location="/var/lib/mysql",
restr = RunnerClass(None, restore_location="/var/lib/mysql/data",
location="filename", checksum="md5")
self.assertEqual(UNZIP + PIPE + SQLDUMP_RESTORE, restr.restore_cmd)
@ -261,7 +267,7 @@ class GuestAgentBackupTest(trove_testtools.TestCase):
restoreBase.RestoreRunner.is_encrypted = True
restoreBase.RestoreRunner.decrypt_key = CRYPTO_KEY
RunnerClass = utils.import_class(RESTORE_SQLDUMP_CLS)
restr = RunnerClass(None, restore_location="/var/lib/mysql",
restr = RunnerClass(None, restore_location="/var/lib/mysql/data",
location="filename", checksum="md5")
self.assertEqual(DECRYPT + PIPE + UNZIP + PIPE + SQLDUMP_RESTORE,
restr.restore_cmd)

View File

@ -223,8 +223,15 @@ class DbaasTest(testtools.TestCase):
def test_load_mysqld_options_error(self, mock_exists):
dbaas.utils.execute = Mock(side_effect=ProcessExecutionError())
self.assertFalse(dbaas.load_mysqld_options())
def test_get_datadir(self):
cnf_value = '[mysqld]\ndatadir=/var/lib/mysql/data'
with patch.object(dbaas, 'read_mycnf', Mock(return_value=cnf_value)):
self.assertEqual('/var/lib/mysql/data',
dbaas.get_datadir(reset_cache=True))
class ResultSetStub(object):

View File

@ -25,6 +25,7 @@ from trove.common.exception import InsufficientSpaceForReplica
from trove.common.exception import ProcessExecutionError
from trove.common import instance as rd_instance
from trove.guestagent import backup
from trove.guestagent.common import operating_system
from trove.guestagent.datastore.mysql.manager import Manager
import trove.guestagent.datastore.mysql.service as dbaas
from trove.guestagent import dbaas as base_dbaas
@ -47,8 +48,10 @@ class GuestAgentManagerTest(testtools.TestCase):
self.origin_mount_points = volume.VolumeDevice.mount_points
self.origin_stop_mysql = dbaas.MySqlApp.stop_db
self.origin_start_mysql = dbaas.MySqlApp.start_mysql
self.origin_update_overrides = dbaas.MySqlApp.update_overrides
self.origin_pkg_is_installed = pkg.Package.pkg_is_installed
self.origin_os_path_exists = os.path.exists
self.origin_chown = operating_system.chown
# set up common mock objects, etc. for replication testing
self.patcher_gfvs = patch(
'trove.guestagent.dbaas.get_filesystem_volume_stats')
@ -71,6 +74,8 @@ class GuestAgentManagerTest(testtools.TestCase):
volume.VolumeDevice.mount_points = self.origin_mount_points
dbaas.MySqlApp.stop_db = self.origin_stop_mysql
dbaas.MySqlApp.start_mysql = self.origin_start_mysql
dbaas.MySqlApp.update_overrides = self.origin_update_overrides
operating_system.chown = self.origin_chown
pkg.Package.pkg_is_installed = self.origin_pkg_is_installed
os.path.exists = self.origin_os_path_exists
# teardown the replication mock objects
@ -220,6 +225,7 @@ class GuestAgentManagerTest(testtools.TestCase):
VolumeDevice.unmount = MagicMock(return_value=None)
dbaas.MySqlApp.stop_db = MagicMock(return_value=None)
dbaas.MySqlApp.start_mysql = MagicMock(return_value=None)
dbaas.MySqlApp.update_overrides = MagicMock(return_value=None)
dbaas.MySqlApp.install_if_needed = MagicMock(return_value=None)
backup.restore = MagicMock(return_value=None)
dbaas.MySqlApp.secure = MagicMock(return_value=None)
@ -231,6 +237,7 @@ class GuestAgentManagerTest(testtools.TestCase):
dbaas.MySqlAdmin.create_user = MagicMock(return_value=None)
dbaas.MySqlAdmin.create_database = MagicMock(return_value=None)
dbaas.MySqlAdmin.enable_root = MagicMock(return_value=None)
operating_system.chown = MagicMock(return_value=None)
os.path.exists = MagicMock(return_value=True)
mock_replication = MagicMock()
mock_replication.enable_as_slave = MagicMock()
@ -263,7 +270,7 @@ class GuestAgentManagerTest(testtools.TestCase):
if backup_info:
backup.restore.assert_any_call(self.context,
backup_info,
'/var/lib/mysql')
'/var/lib/mysql/data')
dbaas.MySqlApp.install_if_needed.assert_any_call(None)
# We don't need to make sure the exact contents are there
dbaas.MySqlApp.secure.assert_any_call(None, None)