Merge lp:~james-page/charms/trusty/percona-cluster/status into lp:~openstack-charmers-archive/charms/trusty/percona-cluster/next

Proposed by James Page on 2015-10-08
Status: Merged
Merged at revision: 79
Proposed branch: lp:~james-page/charms/trusty/percona-cluster/status
Merge into: lp:~openstack-charmers-archive/charms/trusty/percona-cluster/next
Diff against target: 217 lines (+115/-4)
6 files modified
actions/actions.py (+4/-2)
hooks/percona_hooks.py (+2/-0)
hooks/percona_utils.py (+34/-0)
tests/31-test-pause-and-resume.py (+1/-1)
unit_tests/test_percona_hooks.py (+3/-1)
unit_tests/test_percona_utils.py (+71/-0)
To merge this branch: bzr merge lp:~james-page/charms/trusty/percona-cluster/status
Reviewer Review Type Date Requested Status
David Ames 2015-10-08 Resubmit on 2015-10-08
Review via email: mp+273825@code.launchpad.net

Description of the Change

Add status support

To post a comment you must log in.
82. By James Page on 2015-10-08

Drop a comment

charm_lint_check #11507 percona-cluster-next for james-page mp273825
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/11507/

charm_unit_test #10700 percona-cluster-next for james-page mp273825
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/10700/

charm_amulet_test #7212 percona-cluster-next for james-page mp273825
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 124
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/12714788/
Build: http://10.245.162.77:8080/job/charm_amulet_test/7212/

charm_amulet_test #7216 percona-cluster-next for james-page mp273825
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/12715315/
Build: http://10.245.162.77:8080/job/charm_amulet_test/7216/

Liam Young (gnuoy) wrote :

Approved, assuming osci agrees

David Ames (thedac) wrote :

Resubmit to get OSCI to run again.

review: Resubmit
James Page (james-page) wrote :

as osci appears to be asleep running the amulet tests manually.

83. By James Page on 2015-10-09

Set initial state for mysql unit to active, not unknown

charm_lint_check #11620 percona-cluster-next for james-page mp273825
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/11620/

charm_unit_test #10809 percona-cluster-next for james-page mp273825
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/10809/

charm_amulet_test #7270 percona-cluster-next for james-page mp273825
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/12725003/
Build: http://10.245.162.77:8080/job/charm_amulet_test/7270/

84. By James Page on 2015-10-10

Fixup tests deal with single units

85. By James Page on 2015-10-10

Rework assess_status location, call on service resume action

86. By James Page on 2015-10-10

Normalize messages in actions

James Page (james-page) wrote :

I've run the amulet tests by hand as well as the unit and lint tests - all OK.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'actions/actions.py'
2--- actions/actions.py 2015-10-06 15:07:52 +0000
3+++ actions/actions.py 2015-10-10 16:20:17 +0000
4@@ -5,6 +5,7 @@
5
6 from charmhelpers.core.host import service_pause, service_resume
7 from charmhelpers.core.hookenv import action_fail, status_set
8+from percona_utils import assess_status
9
10
11 MYSQL_SERVICE = "mysql"
12@@ -18,7 +19,8 @@
13 if not service_pause(MYSQL_SERVICE):
14 raise Exception("Failed to pause MySQL service.")
15 status_set(
16- "maintenance", "Paused. Use 'resume' action to resume normal service.")
17+ "maintenance",
18+ "Unit paused - use 'resume' action to resume normal service")
19
20
21 def resume(args):
22@@ -27,7 +29,7 @@
23 @raises Exception should the service fail to start."""
24 if not service_resume(MYSQL_SERVICE):
25 raise Exception("Failed to resume MySQL service.")
26- status_set("active", "")
27+ assess_status()
28
29
30 # A dictionary of all the defined actions to callables (which take
31
32=== added symlink 'actions/percona_utils.py'
33=== target is u'../hooks/percona_utils.py'
34=== modified file 'hooks/percona_hooks.py'
35--- hooks/percona_hooks.py 2015-09-23 18:29:21 +0000
36+++ hooks/percona_hooks.py 2015-10-10 16:20:17 +0000
37@@ -61,6 +61,7 @@
38 notify_bootstrapped,
39 is_bootstrapped,
40 get_wsrep_value,
41+ assess_status,
42 )
43 from charmhelpers.contrib.database.mysql import (
44 PerconaClusterHelper,
45@@ -625,6 +626,7 @@
46 hooks.execute(sys.argv)
47 except UnregisteredHookError as e:
48 log('Unknown hook {} - skipping.'.format(e))
49+ assess_status()
50
51
52 if __name__ == '__main__':
53
54=== modified file 'hooks/percona_utils.py'
55--- hooks/percona_utils.py 2015-07-30 09:59:33 +0000
56+++ hooks/percona_utils.py 2015-10-10 16:20:17 +0000
57@@ -25,6 +25,7 @@
58 INFO,
59 WARNING,
60 ERROR,
61+ status_set,
62 )
63 from charmhelpers.fetch import (
64 apt_install,
65@@ -360,3 +361,36 @@
66 (cluster_uuid), DEBUG)
67 for rid in rids:
68 relation_set(relation_id=rid, **{'bootstrap-uuid': cluster_uuid})
69+
70+
71+def cluster_in_sync():
72+ '''
73+ Determines whether the current unit is in sync
74+ with the rest of the cluster
75+ '''
76+ ready = get_wsrep_value('wsrep_ready') or False
77+ sync_status = get_wsrep_value('wsrep_local_state') or 0
78+ if ready and int(sync_status) in [2, 4]:
79+ return True
80+ return False
81+
82+
83+def assess_status():
84+ '''Assess the status of the current unit'''
85+ min_size = config('min-cluster-size')
86+ # Ensure that number of peers > cluster size configuration
87+ if not is_sufficient_peers():
88+ status_set('blocked', 'Insufficient peers to bootstrap cluster')
89+ return
90+
91+ if min_size and int(min_size) > 1:
92+ # Once running, ensure that cluster is in sync
93+ # and has the required peers
94+ if not is_bootstrapped():
95+ status_set('waiting', 'Unit waiting for cluster bootstrap')
96+ elif is_bootstrapped() and cluster_in_sync():
97+ status_set('active', 'Unit is ready and clustered')
98+ else:
99+ status_set('blocked', 'Unit is not in sync')
100+ else:
101+ status_set('active', 'Unit is ready')
102
103=== added symlink 'hooks/update-status'
104=== target is u'percona_hooks.py'
105=== modified file 'tests/31-test-pause-and-resume.py'
106--- tests/31-test-pause-and-resume.py 2015-09-15 12:25:04 +0000
107+++ tests/31-test-pause-and-resume.py 2015-10-10 16:20:17 +0000
108@@ -14,7 +14,7 @@
109 uid = 'percona-cluster/0'
110 unit = self.d.sentry.unit[uid]
111 assert self.is_mysqld_running(unit), 'mysql not running: %s' % uid
112- assert utils.status_get(unit)[0] == "unknown"
113+ assert utils.status_get(unit)[0] == "active"
114
115 action_id = utils.run_action(unit, "pause")
116 assert utils.wait_on_action(action_id), "Pause action failed."
117
118=== modified file 'unit_tests/test_percona_hooks.py'
119--- unit_tests/test_percona_hooks.py 2015-09-29 15:30:53 +0000
120+++ unit_tests/test_percona_hooks.py 2015-10-10 16:20:17 +0000
121@@ -11,7 +11,9 @@
122 'relation_set',
123 'update_nrpe_config',
124 'get_iface_for_address',
125- 'get_netmask_for_address']
126+ 'get_netmask_for_address',
127+ 'is_bootstrapped',
128+ 'is_sufficient_peers']
129
130
131 class TestHaRelation(CharmTestCase):
132
133=== modified file 'unit_tests/test_percona_utils.py'
134--- unit_tests/test_percona_utils.py 2015-08-26 13:22:41 +0000
135+++ unit_tests/test_percona_utils.py 2015-10-10 16:20:17 +0000
136@@ -7,6 +7,8 @@
137 sys.modules['MySQLdb'] = mock.Mock()
138 import percona_utils
139
140+from test_utils import CharmTestCase
141+
142
143 class UtilsTests(unittest.TestCase):
144 def setUp(self):
145@@ -160,3 +162,72 @@
146 self.assertEqual(percona_utils.determine_packages(),
147 ['percona-xtradb-cluster-server-5.5',
148 'percona-xtradb-cluster-client-5.5'])
149+
150+ @mock.patch.object(percona_utils, 'get_wsrep_value')
151+ def test_cluster_in_sync_not_ready(self, _wsrep_value):
152+ _wsrep_value.side_effect = [None, None]
153+ self.assertFalse(percona_utils.cluster_in_sync())
154+
155+ @mock.patch.object(percona_utils, 'get_wsrep_value')
156+ def test_cluster_in_sync_ready_syncing(self, _wsrep_value):
157+ _wsrep_value.side_effect = [True, None]
158+ self.assertFalse(percona_utils.cluster_in_sync())
159+
160+ @mock.patch.object(percona_utils, 'get_wsrep_value')
161+ def test_cluster_in_sync_ready_sync(self, _wsrep_value):
162+ _wsrep_value.side_effect = [True, 4]
163+ self.assertTrue(percona_utils.cluster_in_sync())
164+
165+ @mock.patch.object(percona_utils, 'get_wsrep_value')
166+ def test_cluster_in_sync_ready_sync_donor(self, _wsrep_value):
167+ _wsrep_value.side_effect = [True, 2]
168+ self.assertTrue(percona_utils.cluster_in_sync())
169+
170+
171+TO_PATCH = [
172+ 'status_set',
173+ 'is_sufficient_peers',
174+ 'is_bootstrapped',
175+ 'config',
176+ 'cluster_in_sync',
177+]
178+
179+
180+class TestAssessStatus(CharmTestCase):
181+ def setUp(self):
182+ CharmTestCase.setUp(self, percona_utils, TO_PATCH)
183+
184+ def test_single_unit(self):
185+ self.config.return_value = None
186+ self.is_sufficient_peers.return_value = True
187+ percona_utils.assess_status()
188+ self.status_set.assert_called_with('active', mock.ANY)
189+
190+ def test_insufficient_peers(self):
191+ self.config.return_value = 3
192+ self.is_sufficient_peers.return_value = False
193+ percona_utils.assess_status()
194+ self.status_set.assert_called_with('blocked', mock.ANY)
195+
196+ def test_not_bootstrapped(self):
197+ self.config.return_value = 3
198+ self.is_sufficient_peers.return_value = True
199+ self.is_bootstrapped.return_value = False
200+ percona_utils.assess_status()
201+ self.status_set.assert_called_with('waiting', mock.ANY)
202+
203+ def test_bootstrapped_in_sync(self):
204+ self.config.return_value = 3
205+ self.is_sufficient_peers.return_value = True
206+ self.is_bootstrapped.return_value = True
207+ self.cluster_in_sync.return_value = True
208+ percona_utils.assess_status()
209+ self.status_set.assert_called_with('active', mock.ANY)
210+
211+ def test_bootstrapped_not_in_sync(self):
212+ self.config.return_value = 3
213+ self.is_sufficient_peers.return_value = True
214+ self.is_bootstrapped.return_value = True
215+ self.cluster_in_sync.return_value = False
216+ percona_utils.assess_status()
217+ self.status_set.assert_called_with('blocked', mock.ANY)

Subscribers

People subscribed via source and target branches