Add support to change root password
Change the configured root's password in percona and update the leader settings. Change-Id: I7168a96cac7a3b4df7fcfa1afc6f35076748578b Partial-Bug: 1436093
This commit is contained in:
parent
62ed38b7b2
commit
e7f611ff2e
|
@ -105,6 +105,7 @@ from percona_utils import (
|
|||
pxc_installed,
|
||||
update_bootstrap_uuid,
|
||||
LeaderNoBootstrapUUIDError,
|
||||
update_root_password,
|
||||
)
|
||||
|
||||
|
||||
|
@ -338,6 +339,11 @@ def config_changed():
|
|||
|
||||
open_port(DEFAULT_MYSQL_PORT)
|
||||
|
||||
# the password needs to be updated only if the node was already
|
||||
# bootstrapped
|
||||
if bootstrapped:
|
||||
update_root_password()
|
||||
|
||||
|
||||
@hooks.hook('cluster-relation-joined')
|
||||
def cluster_joined():
|
||||
|
|
|
@ -820,3 +820,30 @@ def pxc_installed():
|
|||
@returns: boolean: indicating installation
|
||||
'''
|
||||
return os.path.exists('/usr/sbin/mysqld')
|
||||
|
||||
|
||||
def update_root_password():
|
||||
"""Update root password if needed
|
||||
|
||||
:returns: `False` when configured password has not changed
|
||||
"""
|
||||
|
||||
cfg = config()
|
||||
if not cfg.changed('root-password'):
|
||||
return False
|
||||
|
||||
m_helper = get_db_helper()
|
||||
|
||||
# password that needs to be set
|
||||
new_root_passwd = cfg['root-password']
|
||||
m_helper.set_mysql_root_password(new_root_passwd)
|
||||
|
||||
# check the password was changed
|
||||
try:
|
||||
m_helper.connect(user='root', password=new_root_passwd)
|
||||
m_helper.execute('select 1;')
|
||||
except OperationalError as ex:
|
||||
log("Error connecting using new passowrd: %s" % str(ex), level=DEBUG)
|
||||
log(('Cannot connect using new password, not updating password in '
|
||||
'the relation'), level=WARNING)
|
||||
return
|
||||
|
|
|
@ -13,6 +13,9 @@ from charmhelpers.contrib.openstack.amulet.deployment import (
|
|||
from charmhelpers.contrib.amulet.utils import AmuletUtils
|
||||
|
||||
|
||||
PXC_ROOT_PASSWD = 'ubuntu'
|
||||
|
||||
|
||||
class BasicDeployment(OpenStackAmuletDeployment):
|
||||
|
||||
utils = AmuletUtils()
|
||||
|
@ -73,7 +76,8 @@ class BasicDeployment(OpenStackAmuletDeployment):
|
|||
def _get_configs(self):
|
||||
"""Configure all of the services."""
|
||||
cfg_percona = {'min-cluster-size': self.units,
|
||||
'vip': self.vip}
|
||||
'vip': self.vip,
|
||||
'root-password': PXC_ROOT_PASSWD}
|
||||
|
||||
cfg_ha = {'debug': True,
|
||||
'corosync_key': ('xZP7GDWV0e8Qs0GxWThXirNNYlScgi3sRTdZk/IXKD'
|
||||
|
@ -240,6 +244,31 @@ class BasicDeployment(OpenStackAmuletDeployment):
|
|||
|
||||
assert self.is_port_open(address=self.vip), 'cannot connect to vip'
|
||||
|
||||
def test_change_root_password(self):
|
||||
"""
|
||||
Change root password and verify the change was effectively applied.
|
||||
"""
|
||||
|
||||
new_root_passwd = 'openstack'
|
||||
|
||||
u = self.master_unit
|
||||
root_password, _ = PXC_ROOT_PASSWD
|
||||
cmd = "mysql -uroot -p{} -e\"select 1;\" ".format(root_password)
|
||||
output, code = u.run(cmd)
|
||||
|
||||
assert code == 0, output
|
||||
|
||||
self.d.configure('percona-cluster', {'root-password': new_root_passwd})
|
||||
|
||||
time.sleep(5) # give some time to the unit to start the hook
|
||||
self.d.sentry.wait() # wait until the hook finishes
|
||||
|
||||
# try to connect using the new root password
|
||||
cmd = "mysql -uroot -p{} -e\"select 1;\" ".format(new_root_passwd)
|
||||
output, code = u.run(cmd)
|
||||
|
||||
assert code == 0, output
|
||||
|
||||
def find_master(self, ha=True):
|
||||
for unit in self.d.sentry['percona-cluster']:
|
||||
if not ha:
|
||||
|
|
|
@ -523,6 +523,8 @@ class TestUpdateBootstrapUUID(CharmTestCase):
|
|||
'relation_set',
|
||||
'is_leader',
|
||||
'leader_set',
|
||||
'config',
|
||||
'leader_get',
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
|
@ -583,3 +585,24 @@ class TestUpdateBootstrapUUID(CharmTestCase):
|
|||
self.get_wsrep_value.side_effect = fake_wsrep
|
||||
self.assertRaises(percona_utils.InconsistentUUIDError,
|
||||
percona_utils.update_bootstrap_uuid)
|
||||
|
||||
@mock.patch('charmhelpers.contrib.database.mysql.leader_set')
|
||||
@mock.patch('charmhelpers.contrib.database.mysql.is_leader')
|
||||
@mock.patch('charmhelpers.contrib.database.mysql.leader_get')
|
||||
def test_update_root_password(self, mock_leader_get, mock_is_leader,
|
||||
mock_leader_set):
|
||||
cur_password = 'openstack'
|
||||
new_password = 'ubuntu'
|
||||
leader_config = {'mysql.passwd': cur_password}
|
||||
mock_leader_get.side_effect = lambda k: leader_config[k]
|
||||
mock_is_leader.return_value = True
|
||||
|
||||
self.config.side_effect = self.test_config.get
|
||||
self.assertFalse(percona_utils.update_root_password())
|
||||
|
||||
self.test_config.set_previous('root-password', cur_password)
|
||||
self.test_config.set('root-password', new_password)
|
||||
percona_utils.update_root_password()
|
||||
|
||||
mock_leader_set.assert_called_with(
|
||||
settings={'mysql.passwd': new_password})
|
||||
|
|
|
@ -70,10 +70,24 @@ class TestConfig(object):
|
|||
|
||||
def __init__(self):
|
||||
self.config = get_default_config()
|
||||
self.config_prev = {}
|
||||
|
||||
def previous(self, k):
|
||||
return self.config_prev[k] if k in self.config_prev else self.config[k]
|
||||
|
||||
def set_previous(self, k, v):
|
||||
self.config_prev[k] = v
|
||||
|
||||
def unset_previous(self, k):
|
||||
if k in self.config_prev:
|
||||
self.config_prev.pop(k)
|
||||
|
||||
def changed(self, k):
|
||||
return self.get(k) != self.previous(k)
|
||||
|
||||
def get(self, attr=None):
|
||||
if not attr:
|
||||
return self.get_all()
|
||||
return self
|
||||
try:
|
||||
return self.config[attr]
|
||||
except KeyError:
|
||||
|
@ -87,6 +101,9 @@ class TestConfig(object):
|
|||
raise KeyError
|
||||
self.config[attr] = value
|
||||
|
||||
def __getitem__(self, k):
|
||||
return self.get(k)
|
||||
|
||||
|
||||
class TestRelation(object):
|
||||
|
||||
|
|
Loading…
Reference in New Issue