Add support for status

This commit is contained in:
James Page 2015-10-10 12:38:04 -07:00
commit 463f8ebc01
8 changed files with 117 additions and 4 deletions

View File

@ -5,6 +5,7 @@ import sys
from charmhelpers.core.host import service_pause, service_resume
from charmhelpers.core.hookenv import action_fail, status_set
from percona_utils import assess_status
MYSQL_SERVICE = "mysql"
@ -18,7 +19,8 @@ def pause(args):
if not service_pause(MYSQL_SERVICE):
raise Exception("Failed to pause MySQL service.")
status_set(
"maintenance", "Paused. Use 'resume' action to resume normal service.")
"maintenance",
"Unit paused - use 'resume' action to resume normal service")
def resume(args):
@ -27,7 +29,7 @@ def resume(args):
@raises Exception should the service fail to start."""
if not service_resume(MYSQL_SERVICE):
raise Exception("Failed to resume MySQL service.")
status_set("active", "")
assess_status()
# A dictionary of all the defined actions to callables (which take

1
actions/percona_utils.py Symbolic link
View File

@ -0,0 +1 @@
../hooks/percona_utils.py

View File

@ -61,6 +61,7 @@ from percona_utils import (
notify_bootstrapped,
is_bootstrapped,
get_wsrep_value,
assess_status,
)
from charmhelpers.contrib.database.mysql import (
PerconaClusterHelper,
@ -625,6 +626,7 @@ def main():
hooks.execute(sys.argv)
except UnregisteredHookError as e:
log('Unknown hook {} - skipping.'.format(e))
assess_status()
if __name__ == '__main__':

View File

@ -25,6 +25,7 @@ from charmhelpers.core.hookenv import (
INFO,
WARNING,
ERROR,
status_set,
)
from charmhelpers.fetch import (
apt_install,
@ -360,3 +361,36 @@ def notify_bootstrapped(cluster_rid=None, cluster_uuid=None):
(cluster_uuid), DEBUG)
for rid in rids:
relation_set(relation_id=rid, **{'bootstrap-uuid': cluster_uuid})
def cluster_in_sync():
'''
Determines whether the current unit is in sync
with the rest of the cluster
'''
ready = get_wsrep_value('wsrep_ready') or False
sync_status = get_wsrep_value('wsrep_local_state') or 0
if ready and int(sync_status) in [2, 4]:
return True
return False
def assess_status():
'''Assess the status of the current unit'''
min_size = config('min-cluster-size')
# Ensure that number of peers > cluster size configuration
if not is_sufficient_peers():
status_set('blocked', 'Insufficient peers to bootstrap cluster')
return
if min_size and int(min_size) > 1:
# Once running, ensure that cluster is in sync
# and has the required peers
if not is_bootstrapped():
status_set('waiting', 'Unit waiting for cluster bootstrap')
elif is_bootstrapped() and cluster_in_sync():
status_set('active', 'Unit is ready and clustered')
else:
status_set('blocked', 'Unit is not in sync')
else:
status_set('active', 'Unit is ready')

1
hooks/update-status Symbolic link
View File

@ -0,0 +1 @@
percona_hooks.py

View File

@ -14,7 +14,7 @@ class PauseResume(basic_deployment.BasicDeployment):
uid = 'percona-cluster/0'
unit = self.d.sentry.unit[uid]
assert self.is_mysqld_running(unit), 'mysql not running: %s' % uid
assert utils.status_get(unit)[0] == "unknown"
assert utils.status_get(unit)[0] == "active"
action_id = utils.run_action(unit, "pause")
assert utils.wait_on_action(action_id), "Pause action failed."

View File

@ -11,7 +11,9 @@ TO_PATCH = ['log', 'config',
'relation_set',
'update_nrpe_config',
'get_iface_for_address',
'get_netmask_for_address']
'get_netmask_for_address',
'is_bootstrapped',
'is_sufficient_peers']
class TestHaRelation(CharmTestCase):

View File

@ -7,6 +7,8 @@ import sys
sys.modules['MySQLdb'] = mock.Mock()
import percona_utils
from test_utils import CharmTestCase
class UtilsTests(unittest.TestCase):
def setUp(self):
@ -160,3 +162,72 @@ class UtilsTests(unittest.TestCase):
self.assertEqual(percona_utils.determine_packages(),
['percona-xtradb-cluster-server-5.5',
'percona-xtradb-cluster-client-5.5'])
@mock.patch.object(percona_utils, 'get_wsrep_value')
def test_cluster_in_sync_not_ready(self, _wsrep_value):
_wsrep_value.side_effect = [None, None]
self.assertFalse(percona_utils.cluster_in_sync())
@mock.patch.object(percona_utils, 'get_wsrep_value')
def test_cluster_in_sync_ready_syncing(self, _wsrep_value):
_wsrep_value.side_effect = [True, None]
self.assertFalse(percona_utils.cluster_in_sync())
@mock.patch.object(percona_utils, 'get_wsrep_value')
def test_cluster_in_sync_ready_sync(self, _wsrep_value):
_wsrep_value.side_effect = [True, 4]
self.assertTrue(percona_utils.cluster_in_sync())
@mock.patch.object(percona_utils, 'get_wsrep_value')
def test_cluster_in_sync_ready_sync_donor(self, _wsrep_value):
_wsrep_value.side_effect = [True, 2]
self.assertTrue(percona_utils.cluster_in_sync())
TO_PATCH = [
'status_set',
'is_sufficient_peers',
'is_bootstrapped',
'config',
'cluster_in_sync',
]
class TestAssessStatus(CharmTestCase):
def setUp(self):
CharmTestCase.setUp(self, percona_utils, TO_PATCH)
def test_single_unit(self):
self.config.return_value = None
self.is_sufficient_peers.return_value = True
percona_utils.assess_status()
self.status_set.assert_called_with('active', mock.ANY)
def test_insufficient_peers(self):
self.config.return_value = 3
self.is_sufficient_peers.return_value = False
percona_utils.assess_status()
self.status_set.assert_called_with('blocked', mock.ANY)
def test_not_bootstrapped(self):
self.config.return_value = 3
self.is_sufficient_peers.return_value = True
self.is_bootstrapped.return_value = False
percona_utils.assess_status()
self.status_set.assert_called_with('waiting', mock.ANY)
def test_bootstrapped_in_sync(self):
self.config.return_value = 3
self.is_sufficient_peers.return_value = True
self.is_bootstrapped.return_value = True
self.cluster_in_sync.return_value = True
percona_utils.assess_status()
self.status_set.assert_called_with('active', mock.ANY)
def test_bootstrapped_not_in_sync(self):
self.config.return_value = 3
self.is_sufficient_peers.return_value = True
self.is_bootstrapped.return_value = True
self.cluster_in_sync.return_value = False
percona_utils.assess_status()
self.status_set.assert_called_with('blocked', mock.ANY)