Fix Percona XtraDB Cluster guest to work with v5.6
The current implmentation of Percona clusters only supports PXC 5.5. To make the implementation work with v5.6, some changes need to be made to the base Mysql manager. The biggest change is that we can no longer store the os_admin client credentials in the server my.cnf file. This commit moves those credentials to a .my.cnf file stored in the trove homedir. This will be read by the guest when attempting sqlchemy connections to the local mysql database and will also be picked up automatically by other mysql clients (such as mysqladmin). Also, since PXC 5.6 requires PXB 2.3, this commit fixes the issue previously discovered with that combination. The previous fix was to pin PXB to v2.2. The fix is to specify host=127.0.0.1 in the client section of my.cnf. Change-Id: Ib73b4f8ba40ddf211d0ec88069c4807186fce139 Parial-bug: 1532969
This commit is contained in:
parent
4a2749c3e1
commit
293dafb565
|
@ -567,6 +567,7 @@ class BaseMySqlApp(object):
|
|||
"""Prepares DBaaS on a Guest container."""
|
||||
|
||||
TIME_OUT = 1000
|
||||
CFG_CODEC = IniCodec()
|
||||
|
||||
@property
|
||||
def local_sql_client(self):
|
||||
|
@ -577,7 +578,7 @@ class BaseMySqlApp(object):
|
|||
return self._keep_alive_connection_cls
|
||||
|
||||
configuration_manager = ConfigurationManager(
|
||||
MYSQL_CONFIG, MYSQL_OWNER, MYSQL_OWNER, IniCodec(), requires_root=True,
|
||||
MYSQL_CONFIG, MYSQL_OWNER, MYSQL_OWNER, CFG_CODEC, requires_root=True,
|
||||
override_strategy=ImportOverrideStrategy(CNF_INCLUDE_DIR, CNF_EXT))
|
||||
|
||||
def get_engine(self):
|
||||
|
@ -601,7 +602,9 @@ class BaseMySqlApp(object):
|
|||
|
||||
@classmethod
|
||||
def get_auth_password(cls):
|
||||
return cls.configuration_manager.get_value('client').get('password')
|
||||
auth_config = operating_system.read_file(
|
||||
cls.get_client_auth_file(), codec=cls.CFG_CODEC)
|
||||
return auth_config['client']['password']
|
||||
|
||||
@classmethod
|
||||
def get_data_dir(cls):
|
||||
|
@ -613,6 +616,10 @@ class BaseMySqlApp(object):
|
|||
cls.configuration_manager.apply_system_override(
|
||||
{MySQLConfParser.SERVER_CONF_SECTION: {'datadir': value}})
|
||||
|
||||
@classmethod
|
||||
def get_client_auth_file(self):
|
||||
return guestagent_utils.build_file_path("~", ".my.cnf")
|
||||
|
||||
def __init__(self, status, local_sql_client, keep_alive_connection_cls):
|
||||
"""By default login with root no password for initial setup."""
|
||||
self.state_change_wait_time = CONF.state_change_wait_time
|
||||
|
@ -684,8 +691,11 @@ class BaseMySqlApp(object):
|
|||
self.wipe_ib_logfiles()
|
||||
|
||||
def _save_authentication_properties(self, admin_password):
|
||||
self.configuration_manager.apply_system_override(
|
||||
{'client': {'user': ADMIN_USER_NAME, 'password': admin_password}})
|
||||
client_sect = {'client': {'user': ADMIN_USER_NAME,
|
||||
'password': admin_password,
|
||||
'host': '127.0.0.1'}}
|
||||
operating_system.write_file(self.get_client_auth_file(),
|
||||
client_sect, codec=self.CFG_CODEC)
|
||||
|
||||
def secure_root(self, secure_remote_root=True):
|
||||
with self.local_sql_client(self.get_engine()) as client:
|
||||
|
|
|
@ -9,7 +9,7 @@ wsrep_slave_threads=8
|
|||
wsrep_provider=/usr/lib/libgalera_smm.so
|
||||
wsrep_provider_options="gcache.size={{ (128 * flavor['ram']/512)|int }}M; gcache.page_size=1G"
|
||||
|
||||
wsrep_sst_method=xtrabackup
|
||||
wsrep_sst_method=xtrabackup-v2
|
||||
wsrep_sst_auth="{{ replication_user_pass }}"
|
||||
|
||||
wsrep_cluster_address="gcomm://{{ cluster_ips }}"
|
||||
|
|
|
@ -206,18 +206,20 @@ class DbaasTest(trove_testtools.TestCase):
|
|||
self.assertEqual(1, mock_execute.call_count)
|
||||
mock_remove.assert_not_called()
|
||||
|
||||
@patch.object(MySqlApp.configuration_manager, 'get_value',
|
||||
return_value=MagicMock({'get': 'some password'}))
|
||||
def test_get_auth_password(self, get_cnf_mock):
|
||||
@patch.object(operating_system, 'read_file',
|
||||
return_value={'client':
|
||||
{'password': 'some password'}})
|
||||
def test_get_auth_password(self, read_file_mock):
|
||||
password = MySqlApp.get_auth_password()
|
||||
get_cnf_mock.assert_called_once_with('client')
|
||||
get_cnf_mock.return_value.get.assert_called_once_with('password')
|
||||
self.assertEqual(get_cnf_mock.return_value.get.return_value, password)
|
||||
read_file_mock.assert_called_once_with(MySqlApp.get_client_auth_file(),
|
||||
codec=MySqlApp.CFG_CODEC)
|
||||
self.assertEqual("some password", password)
|
||||
|
||||
@patch.object(MySqlApp.configuration_manager, 'get_value',
|
||||
side_effect=RuntimeError('Error'))
|
||||
def test_get_auth_password_error(self, get_cnf_mock):
|
||||
self.assertRaises(RuntimeError, MySqlApp.get_auth_password)
|
||||
@patch.object(operating_system, 'read_file',
|
||||
side_effect=RuntimeError('read_file error'))
|
||||
def test_get_auth_password_error(self, _):
|
||||
self.assertRaisesRegexp(RuntimeError, "read_file error",
|
||||
MySqlApp.get_auth_password)
|
||||
|
||||
def test_service_discovery(self):
|
||||
with patch.object(os.path, 'isfile', return_value=True):
|
||||
|
@ -418,6 +420,8 @@ class MySqlAdminTest(trove_testtools.TestCase):
|
|||
# trove.guestagent.common.configuration import ConfigurationManager
|
||||
dbaas.orig_configuration_manager = dbaas.MySqlApp.configuration_manager
|
||||
dbaas.MySqlApp.configuration_manager = Mock()
|
||||
dbaas.orig_get_auth_password = dbaas.MySqlApp.get_auth_password
|
||||
dbaas.MySqlApp.get_auth_password = Mock()
|
||||
|
||||
self.mySqlAdmin = MySqlAdmin()
|
||||
|
||||
|
@ -427,6 +431,8 @@ class MySqlAdminTest(trove_testtools.TestCase):
|
|||
self.orig_MySQLUser_is_valid_user_name)
|
||||
dbaas.MySqlApp.configuration_manager = \
|
||||
dbaas.orig_configuration_manager
|
||||
dbaas.MySqlApp.get_auth_password = \
|
||||
dbaas.orig_get_auth_password
|
||||
super(MySqlAdminTest, self).tearDown()
|
||||
|
||||
def test__associate_dbs(self):
|
||||
|
@ -1056,20 +1062,19 @@ class MySqlAppTest(trove_testtools.TestCase):
|
|||
return_value='some_password')
|
||||
def test_reset_configuration(self, auth_pwd_mock):
|
||||
save_cfg_mock = Mock()
|
||||
apply_mock = Mock()
|
||||
save_auth_mock = Mock()
|
||||
wipe_ib_mock = Mock()
|
||||
|
||||
configuration = {'config_contents': 'some junk'}
|
||||
|
||||
self.mySqlApp.configuration_manager.save_configuration = save_cfg_mock
|
||||
self.mySqlApp.configuration_manager.apply_system_override = apply_mock
|
||||
self.mySqlApp._save_authentication_properties = save_auth_mock
|
||||
self.mySqlApp.wipe_ib_logfiles = wipe_ib_mock
|
||||
self.mySqlApp.reset_configuration(configuration=configuration)
|
||||
|
||||
save_cfg_mock.assert_called_once_with('some junk')
|
||||
apply_mock.assert_called_once_with(
|
||||
{'client': {'user': dbaas_base.ADMIN_USER_NAME,
|
||||
'password': auth_pwd_mock.return_value}})
|
||||
save_auth_mock.assert_called_once_with(
|
||||
auth_pwd_mock.return_value)
|
||||
wipe_ib_mock.assert_called_once_with()
|
||||
|
||||
@patch.object(utils, 'execute_with_timeout', return_value=('0', ''))
|
||||
|
@ -1355,6 +1360,16 @@ class MySqlAppTest(trove_testtools.TestCase):
|
|||
self.assertTrue(pkg_install.called)
|
||||
self.assert_reported_status(rd_instance.ServiceStatuses.NEW)
|
||||
|
||||
@patch.object(operating_system, 'write_file')
|
||||
def test_save_authentication_properties(self, write_file_mock):
|
||||
self.mySqlApp._save_authentication_properties("some_password")
|
||||
write_file_mock.assert_called_once_with(
|
||||
MySqlApp.get_client_auth_file(),
|
||||
{'client': {'host': '127.0.0.1',
|
||||
'password': 'some_password',
|
||||
'user': dbaas_base.ADMIN_USER_NAME}},
|
||||
codec=MySqlApp.CFG_CODEC)
|
||||
|
||||
@patch.object(utils, 'generate_random_password',
|
||||
return_value='some_password')
|
||||
@patch.object(dbaas_base, 'clear_expired_password')
|
||||
|
@ -1472,18 +1487,16 @@ class MySqlAppTest(trove_testtools.TestCase):
|
|||
self.assertFalse(self.mySqlApp.start_mysql.called)
|
||||
self.assert_reported_status(rd_instance.ServiceStatuses.NEW)
|
||||
|
||||
@patch.object(dbaas.MySqlApp, '_save_authentication_properties')
|
||||
@patch.object(dbaas, 'get_engine',
|
||||
return_value=MagicMock(name='get_engine'))
|
||||
def test_reset_admin_password(self, mock_engine):
|
||||
def test_reset_admin_password(self, mock_engine, mock_save_auth):
|
||||
with patch.object(dbaas.MySqlApp, 'local_sql_client',
|
||||
return_value=self.mock_client):
|
||||
config_manager = self.mySqlApp.configuration_manager
|
||||
config_manager.apply_system_override = Mock()
|
||||
self.mySqlApp._create_admin_user = Mock()
|
||||
self.mySqlApp.reset_admin_password("newpassword")
|
||||
self.assertEqual(1,
|
||||
config_manager.apply_system_override.call_count)
|
||||
self.assertEqual(1, self.mySqlApp._create_admin_user.call_count)
|
||||
mock_save_auth.assert_called_once_with("newpassword")
|
||||
|
||||
|
||||
class TextClauseMatcher(object):
|
||||
|
|
Loading…
Reference in New Issue