Merge lp:~gnuoy/charm-helpers/current-dc-leader into lp:charm-helpers

Proposed by Liam Young
Status: Merged
Merged at revision: 374
Proposed branch: lp:~gnuoy/charm-helpers/current-dc-leader
Merge into: lp:charm-helpers
Diff against target: 112 lines (+63/-0)
2 files modified
charmhelpers/contrib/hahelpers/cluster.py (+25/-0)
tests/contrib/hahelpers/test_cluster_utils.py (+38/-0)
To merge this branch: bzr merge lp:~gnuoy/charm-helpers/current-dc-leader
Reviewer Review Type Date Requested Status
Adam Collard (community) Needs Fixing
James Page Approve
Review via email: mp+259123@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Liam Young (gnuoy) wrote :

This mp implements freyes suggestion of using pacemaker Designated Controller as a way to determine leadership. See https://bugs.launchpad.net/charms/+source/percona-cluster/+bug/1452365/comments/9

375. By Liam Young

Use constant for DC resource string and add doc string

Revision history for this message
James Page (james-page) wrote :

Minor niggle - please fix and merge!

review: Approve
376. By Liam Young

Fix unit test for is_crm_leader to use DC_RESOURCE_NAME

Revision history for this message
Adam Collard (adam-collard) :
review: Needs Fixing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'charmhelpers/contrib/hahelpers/cluster.py'
2--- charmhelpers/contrib/hahelpers/cluster.py 2015-02-16 14:26:57 +0000
3+++ charmhelpers/contrib/hahelpers/cluster.py 2015-05-15 09:18:20 +0000
4@@ -52,6 +52,8 @@
5 bool_from_string,
6 )
7
8+DC_RESOURCE_NAME = 'DC'
9+
10
11 class HAIncompleteConfig(Exception):
12 pass
13@@ -95,6 +97,27 @@
14 return False
15
16
17+def is_crm_dc():
18+ """
19+ Determine leadership by querying the pacemaker Designated Controller
20+ """
21+ cmd = ['crm', 'status']
22+ try:
23+ status = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
24+ if not isinstance(status, six.text_type):
25+ status = six.text_type(status, "utf-8")
26+ except subprocess.CalledProcessError:
27+ status = None
28+ current_dc = ''
29+ for line in status.split('\n'):
30+ if line.startswith('Current DC'):
31+ # Current DC: juju-lytrusty-machine-2 (168108163) - partition with quorum
32+ current_dc = line.split(':')[1].split()[0]
33+ if current_dc == get_unit_hostname():
34+ return True
35+ return False
36+
37+
38 @retry_on_exception(5, base_delay=2, exc_type=CRMResourceNotFound)
39 def is_crm_leader(resource, retry=False):
40 """
41@@ -104,6 +127,8 @@
42 We allow this operation to be retried to avoid the possibility of getting a
43 false negative. See LP #1396246 for more info.
44 """
45+ if resource == DC_RESOURCE_NAME:
46+ return is_crm_dc()
47 cmd = ['crm', 'resource', 'show', resource]
48 try:
49 status = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
50
51=== modified file 'tests/contrib/hahelpers/test_cluster_utils.py'
52--- tests/contrib/hahelpers/test_cluster_utils.py 2015-01-06 15:28:29 +0000
53+++ tests/contrib/hahelpers/test_cluster_utils.py 2015-05-15 09:18:20 +0000
54@@ -6,6 +6,24 @@
55
56 import charmhelpers.contrib.hahelpers.cluster as cluster_utils
57
58+CRM_STATUS = b'''
59+Last updated: Thu May 14 14:46:35 2015
60+Last change: Thu May 14 14:43:51 2015 via crmd on juju-trusty-machine-1
61+Stack: corosync
62+Current DC: juju-trusty-machine-2 (168108171) - partition with quorum
63+Version: 1.1.10-42f2063
64+3 Nodes configured
65+4 Resources configured
66+
67+
68+Online: [ juju-trusty-machine-1 juju-trusty-machine-2 juju-trusty-machine-3 ]
69+
70+ Resource Group: grp_percona_cluster
71+ res_mysql_vip (ocf::heartbeat:IPaddr2): Started juju-trusty-machine-1
72+ Clone Set: cl_mysql_monitor [res_mysql_monitor]
73+ Started: [ juju-trusty-machine-1 juju-trusty-machine-2 juju-trusty-machine-3 ]
74+'''
75+
76
77 class ClusterUtilsTests(TestCase):
78 def setUp(self):
79@@ -41,6 +59,20 @@
80 self.assertFalse(cluster_utils.is_clustered())
81
82 @patch('subprocess.check_output')
83+ def test_is_crm_dc(self, check_output):
84+ '''It determines its unit is leader'''
85+ self.get_unit_hostname.return_value = 'juju-trusty-machine-2'
86+ check_output.return_value = CRM_STATUS
87+ self.assertTrue(cluster_utils.is_crm_dc())
88+
89+ @patch('subprocess.check_output')
90+ def test_is_crm_dc_false(self, check_output):
91+ '''It determines its unit is leader'''
92+ self.get_unit_hostname.return_value = 'juju-trusty-machine-1'
93+ check_output.return_value = CRM_STATUS
94+ self.assertFalse(cluster_utils.is_crm_dc())
95+
96+ @patch('subprocess.check_output')
97 def test_is_crm_leader(self, check_output):
98 '''It determines its unit is leader'''
99 self.get_unit_hostname.return_value = 'node1'
100@@ -79,6 +111,12 @@
101 self.assertFalse(cluster_utils.is_crm_leader('vip'))
102 self.assertFalse(mock_time.called)
103
104+ @patch.object(cluster_utils, 'is_crm_dc')
105+ def test_is_crm_leader_dc_resource(self, _is_crm_dc):
106+ '''Call out to is_crm_dc'''
107+ cluster_utils.is_crm_leader(cluster_utils.DC_RESOURCE_NAME)
108+ _is_crm_dc.assert_called_with()
109+
110 def test_peer_units(self):
111 '''It lists all peer units for cluster relation'''
112 peers = ['peer_node/1', 'peer_node/2']

Subscribers

People subscribed via source and target branches