Merge lp:~hopem/charms/trusty/percona-cluster/fix-1389670 into lp:~openstack-charmers-archive/charms/trusty/percona-cluster/trunk

Proposed by Edward Hope-Morley
Status: Merged
Merged at revision: 43
Proposed branch: lp:~hopem/charms/trusty/percona-cluster/fix-1389670
Merge into: lp:~openstack-charmers-archive/charms/trusty/percona-cluster/trunk
Diff against target: 325 lines (+115/-87)
4 files modified
hooks/mysql.py (+30/-28)
hooks/percona_hooks.py (+47/-35)
hooks/percona_utils.py (+8/-6)
unit_tests/test_mysql.py (+30/-18)
To merge this branch: bzr merge lp:~hopem/charms/trusty/percona-cluster/fix-1389670
Reviewer Review Type Date Requested Status
Liam Young (community) Approve
Review via email: mp+247596@code.launchpad.net
To post a comment you must log in.
45. By Edward Hope-Morley

more log cleanup

46. By Edward Hope-Morley

fixed no hostname case and updated unit test

Revision history for this message
Billy Olsen (billy-olsen) :
47. By Edward Hope-Morley

cleanup

Revision history for this message
Liam Young (gnuoy) wrote :

Approve

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hooks/mysql.py'
2--- hooks/mysql.py 2014-11-24 12:12:15 +0000
3+++ hooks/mysql.py 2015-01-28 18:54:36 +0000
4@@ -11,11 +11,11 @@
5 from charmhelpers.core.host import pwgen, mkdir, write_file
6 from charmhelpers.core.hookenv import (
7 relation_get,
8- relation_ids,
9 related_units,
10 service_name,
11 unit_get,
12 log,
13+ DEBUG,
14 INFO,
15 )
16 from charmhelpers.core.hookenv import config as config_get
17@@ -331,36 +331,38 @@
18 return mysql_config
19
20
21-def get_allowed_units(database, username):
22+def get_allowed_units(database, username, relation_id=None):
23 m_helper = MySQLHelper()
24 m_helper.connect(password=get_mysql_root_password())
25 allowed_units = set()
26- for relid in relation_ids('shared-db'):
27- for unit in related_units(relid):
28- hosts = relation_get(attribute="%s_%s" % (database, 'hostname'),
29- unit=unit, rid=relid)
30- if not hosts:
31- hosts = [relation_get(attribute='private-address', unit=unit,
32- rid=relid)]
33- else:
34- # hostname can be json-encoded list of hostnames
35- try:
36- _hosts = json.loads(hosts)
37- except ValueError:
38- pass
39+ for unit in related_units(relation_id):
40+ settings = relation_get(rid=relation_id, unit=unit)
41+ # First check for setting with prefix, then without
42+ for attr in ["%s_hostname" % (database), 'hostname']:
43+ hosts = settings.get(attr, None)
44+ if hosts:
45+ break
46+
47+ if hosts:
48+ # hostname can be json-encoded list of hostnames
49+ try:
50+ hosts = json.loads(hosts)
51+ except ValueError:
52+ hosts = [hosts]
53+ else:
54+ hosts = [settings['private-address']]
55+
56+ if hosts:
57+ for host in hosts:
58+ if m_helper.grant_exists(database, username, host):
59+ log("Grant exists for host '%s' on db '%s'" %
60+ (host, database), level=DEBUG)
61+ if unit not in allowed_units:
62+ allowed_units.add(unit)
63 else:
64- hosts = _hosts
65-
66- if not isinstance(hosts, list):
67- hosts = [hosts]
68-
69- if hosts:
70- for host in hosts:
71- log("Checking host '%s' grant" % (host), level=INFO)
72- if m_helper.grant_exists(database, username, host):
73- if unit not in allowed_units:
74- allowed_units.add(unit)
75- else:
76- log("No hosts found for grant check", level=INFO)
77+ log("Grant does NOT exist for host '%s' on db '%s'" %
78+ (host, database), level=DEBUG)
79+ else:
80+ log("No hosts found for grant check", level=INFO)
81
82 return allowed_units
83
84=== modified file 'hooks/percona_hooks.py'
85--- hooks/percona_hooks.py 2014-12-17 18:59:55 +0000
86+++ hooks/percona_hooks.py 2015-01-28 18:54:36 +0000
87@@ -18,12 +18,12 @@
88 config,
89 remote_unit,
90 relation_type,
91+ DEBUG,
92 INFO,
93 )
94 from charmhelpers.core.host import (
95 service_restart,
96 file_hash,
97- write_file,
98 lsb_release,
99 )
100 from charmhelpers.core.templating import render
101@@ -231,6 +231,23 @@
102 return unit_get('private-address')
103
104
105+def configure_db_for_hosts(hosts, database, username):
106+ """Hosts may be a json-encoded list of hosts or a single hostname."""
107+ try:
108+ hosts = json.loads(hosts)
109+ log("Multiple hostnames provided by relation: %s" % (', '.join(hosts)),
110+ level=DEBUG)
111+ except ValueError:
112+ log("Single hostname provided by relation: %s" % (hosts),
113+ level=DEBUG)
114+ hosts = [hosts]
115+
116+ for host in hosts:
117+ password = configure_db(host, database, username)
118+
119+ return password
120+
121+
122 # TODO: This could be a hook common between mysql and percona-cluster
123 @hooks.hook('shared-db-relation-changed')
124 def shared_db_changed(relation_id=None, unit=None):
125@@ -270,25 +287,18 @@
126 database = settings['database']
127 username = settings['username']
128
129- # Hostname can be json-encoded list of hostnames
130- try:
131- hostname = json.loads(hostname)
132- except ValueError:
133- pass
134-
135- if isinstance(hostname, list):
136- for host in hostname:
137- password = configure_db(host, database, username)
138- else:
139- password = configure_db(hostname, database, username)
140-
141- allowed_units = unit_sorted(get_allowed_units(database, username))
142+ # NOTE: do this before querying access grants
143+ password = configure_db_for_hosts(hostname, database, username)
144+
145+ allowed_units = unit_sorted(get_allowed_units(database, username,
146+ relation_id=relation_id))
147 allowed_units = ' '.join(allowed_units)
148+ relation_set(relation_id=relation_id, allowed_units=allowed_units)
149+
150 db_host = get_db_host(hostname)
151 peer_store_and_set(relation_id=relation_id,
152 db_host=db_host,
153- password=password,
154- allowed_units=allowed_units)
155+ password=password)
156 else:
157 # Process multiple database setup requests.
158 # from incoming relation data:
159@@ -316,34 +326,36 @@
160 databases[db] = {}
161 databases[db][x] = v
162
163+ allowed_units = {}
164 return_data = {}
165 for db in databases:
166 if singleset.issubset(databases[db]):
167 database = databases[db]['database']
168 hostname = databases[db]['hostname']
169 username = databases[db]['username']
170- try:
171- hostname = json.loads(hostname)
172- except ValueError:
173- pass
174-
175- if isinstance(hostname, list):
176- for host in hostname:
177- password = configure_db(host, database, username)
178- else:
179- password = configure_db(hostname, database, username)
180-
181- return_data['_'.join([db, 'password'])] = password
182- return_data['_'.join([db, 'allowed_units'])] = \
183- " ".join(unit_sorted(get_allowed_units(database,
184- username)))
185+
186+ # NOTE: do this before querying access grants
187+ password = configure_db_for_hosts(hostname, database, username)
188+
189+ a_units = get_allowed_units(database, username,
190+ relation_id=relation_id)
191+ a_units = ' '.join(unit_sorted(a_units))
192+ allowed_units['%s_allowed_units' % (db)] = a_units
193+
194+ return_data['%s_password' % (db)] = password
195 db_host = get_db_host(hostname)
196
197- if len(return_data) > 0:
198- peer_store_and_set(relation_id=relation_id,
199+ if allowed_units:
200+ relation_set(relation_id=relation_id, **allowed_units)
201+ else:
202+ log("No allowed_units - not setting relation settings",
203+ level=DEBUG)
204+
205+ if return_data:
206+ peer_store_and_set(relation_id=relation_id, db_host=db_host,
207 **return_data)
208- peer_store_and_set(relation_id=relation_id,
209- db_host=db_host)
210+ else:
211+ log("No return data - not setting relation settings", level=DEBUG)
212
213 peer_store_and_set(relation_id=relation_id,
214 relation_settings={'access-network': access_network})
215
216=== modified file 'hooks/percona_utils.py'
217--- hooks/percona_utils.py 2014-12-17 21:03:54 +0000
218+++ hooks/percona_utils.py 2015-01-28 18:54:36 +0000
219@@ -16,7 +16,7 @@
220 local_unit,
221 config,
222 log,
223- INFO
224+ DEBUG,
225 )
226 from charmhelpers.fetch import (
227 apt_install,
228@@ -104,11 +104,12 @@
229 if not hostname or hostname in hosts:
230 log("(unit=%s) Ignoring hostname '%s' provided by cluster "
231 "relation for addr %s" %
232- (unit, hostname, private_address))
233+ (unit, hostname, private_address), level=DEBUG)
234 continue
235 else:
236 log("(unit=%s) hostname '%s' provided by cluster relation "
237- "for addr %s" % (unit, hostname, private_address))
238+ "for addr %s" % (unit, hostname, private_address),
239+ level=DEBUG)
240
241 hosts_map[private_address] = hostname
242 hosts.append(hostname)
243@@ -175,8 +176,8 @@
244 with open(HOSTS_FILE, 'r') as hosts:
245 lines = hosts.readlines()
246
247- log("Updating hosts file with: %s (current: %s)" % (map, lines),
248- level=INFO)
249+ log("Updating %s with: %s (current: %s)" % (HOSTS_FILE, map, lines),
250+ level=DEBUG)
251
252 newlines = []
253 for ip, hostname in map.items():
254@@ -189,7 +190,8 @@
255 if len(line) < 2 or not (_line[0] == ip or hostname in _line[1:]):
256 keepers.append(line)
257 else:
258- log("Removing line '%s' from hosts file" % (line))
259+ log("Marking line '%s' for update or removal" % (line.strip()),
260+ level=DEBUG)
261
262 lines = keepers
263 newlines.append("%s %s\n" % (ip, hostname))
264
265=== modified file 'unit_tests/test_mysql.py'
266--- unit_tests/test_mysql.py 2014-10-15 16:09:41 +0000
267+++ unit_tests/test_mysql.py 2015-01-28 18:54:36 +0000
268@@ -15,27 +15,39 @@
269 @mock.patch('mysql.MySQLHelper', autospec=True)
270 @mock.patch('mysql.relation_get')
271 @mock.patch('mysql.related_units')
272- @mock.patch('mysql.relation_ids')
273 @mock.patch('mysql.log')
274- def test_get_allowed_units(self, mock_log, mock_relation_ids,
275- mock_related_units,
276+ def test_get_allowed_units(self, mock_log, mock_related_units,
277 mock_relation_get, mock_helper,
278 mock_get_password):
279- mock_relation_ids.return_value = ['r1']
280- mock_related_units.return_value = ['ru1', 'ru2']
281-
282- def mock_rel_get(attribute, unit, rid):
283- if unit == 'ru2':
284- d = {'private-address': '1.2.3.4',
285- 'dbA_hostname': json.dumps(['2.3.4.5', '6.7.8.9'])}
286- else:
287- d = {'private-address': '1.2.3.4'}
288-
289- return d.get(attribute, None)
290+
291+ def mock_rel_get(unit, rid):
292+ if unit == 'unit/0':
293+ # Non-prefixed settings
294+ d = {'private-address': '10.0.0.1',
295+ 'hostname': 'hostA'}
296+ elif unit == 'unit/1':
297+ # Containing prefixed settings
298+ d = {'private-address': '10.0.0.2',
299+ 'dbA_hostname': json.dumps(['10.0.0.2', '2001:db8:1::2'])}
300+ elif unit == 'unit/2':
301+ # No hostname
302+ d = {'private-address': '10.0.0.3'}
303+
304+ return d
305
306 mock_relation_get.side_effect = mock_rel_get
307+ mock_related_units.return_value = ['unit/0', 'unit/1', 'unit/2']
308+
309 units = mysql.get_allowed_units('dbA', 'userA')
310- mock_helper.return_value.grant_exists.assert_called_with('dbA',
311- 'userA',
312- '6.7.8.9')
313- self.assertEqual(units, set(['ru1', 'ru2']))
314+
315+ calls = [mock.call('dbA', 'userA', 'hostA'),
316+ mock.call().__nonzero__(),
317+ mock.call('dbA', 'userA', '10.0.0.2'),
318+ mock.call().__nonzero__(),
319+ mock.call('dbA', 'userA', '2001:db8:1::2'),
320+ mock.call().__nonzero__(),
321+ mock.call('dbA', 'userA', '10.0.0.3'),
322+ mock.call().__nonzero__()]
323+
324+ mock_helper.return_value.grant_exists.assert_has_calls(calls)
325+ self.assertEqual(units, set(['unit/0', 'unit/1', 'unit/2']))

Subscribers

People subscribed via source and target branches

to status/vote changes: