Merge lp:~gnuoy/charms/trusty/mysql/lp-1353135 into lp:charms/trusty/mysql

Proposed by Liam Young
Status: Merged
Merged at revision: 125
Proposed branch: lp:~gnuoy/charms/trusty/mysql/lp-1353135
Merge into: lp:charms/trusty/mysql
Diff against target: 102 lines (+38/-3)
2 files modified
hooks/common.py (+3/-1)
hooks/shared_db_relations.py (+35/-2)
To merge this branch: bzr merge lp:~gnuoy/charms/trusty/mysql/lp-1353135
Reviewer Review Type Date Requested Status
Review Queue (community) cbt Approve
Cory Johns (community) Approve
charmers Pending
Review via email: mp+230932@code.launchpad.net

Description of the change

Set a list of allowed_units which the client units can query to see if their permissions have been setup yet. The reason for this is to allow the client to work around a race condition which occurs when a service has multiple units:

1) A service consisting of multiple units joins mysql and triggers mysql to run shared-db-changed for each unit in turn. But as soon as shared-db-changed has been run for the *first* time mysql runs relation set publishing the password.

2) All units in the client service then run their shared-db-changed hook in response to the relation set that mysql issued when it did the *first* run of shared-db-changed. At this point permissions have only been granted to one unit and the rest will fail if they try and access the db.

This is the same behaviour as the postgres charm which was added in response to Bug #1187508

To post a comment you must log in.
129. By Liam Young

Fixed bug causing slave-relation-changed to fail when constructing the allowed list when multiple dbs were specified

Revision history for this message
Cory Johns (johnsca) wrote :

Liam,

Thank you for this fix. It looks good and works as expected, though the affected charms will need to be updated to make use of the new field, of course (the charm I was testing this with errored and blocked the list from being fully updated, but one unit did get the full list and another unit got a partial list before being blocked by the other units failing).

review: Approve
Revision history for this message
Review Queue (review-queue) wrote :

The results (PASS) are in and available here: http://reports.vapour.ws/charm-tests/charm-bundle-test-962-results

review: Approve (cbt)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hooks/common.py'
2--- hooks/common.py 2014-03-04 17:28:10 +0000
3+++ hooks/common.py 2014-08-27 09:57:20 +0000
4@@ -84,6 +84,8 @@
5
6 def grant_exists(db_name, db_user, remote_ip):
7 cursor = get_db_cursor()
8+ priv_string = "GRANT ALL PRIVILEGES ON `{}`.* " \
9+ "TO '{}'@'{}'".format(db_name, db_user, remote_ip)
10 try:
11 cursor.execute("SHOW GRANTS for '{}'@'{}'".format(db_user,
12 remote_ip))
13@@ -93,7 +95,7 @@
14 return False
15 finally:
16 cursor.close()
17- return "GRANT ALL PRIVILEGES ON `{}`".format(db_name) in grants
18+ return priv_string in grants
19
20
21 def create_grant(db_name, db_user,
22
23=== modified file 'hooks/shared_db_relations.py'
24--- hooks/shared_db_relations.py 2014-06-02 19:52:50 +0000
25+++ hooks/shared_db_relations.py 2014-08-27 09:57:20 +0000
26@@ -19,6 +19,7 @@
27 import os
28 import lib.utils as utils
29 import lib.cluster_utils as cluster
30+from charmhelpers.core import hookenv
31
32 LEADER_RES = 'res_mysql_vip'
33
34@@ -33,8 +34,30 @@
35 'json']))
36
37
38+def unit_sorted(units):
39+ """Return a sorted list of unit names."""
40+ return sorted(
41+ units, lambda a, b: cmp(int(a.split('/')[-1]), int(b.split('/')[-1])))
42+
43+
44+def get_unit_addr(relid, unitid):
45+ return hookenv.relation_get(attribute='private-address',
46+ unit=unitid,
47+ rid=relid)
48+
49+
50 def shared_db_changed():
51
52+ def get_allowed_units(database, username):
53+ allowed_units = set()
54+ for relid in hookenv.relation_ids('shared-db'):
55+ for unit in hookenv.related_units(relid):
56+ if grant_exists(database,
57+ username,
58+ get_unit_addr(relid, unit)):
59+ allowed_units.add(unit)
60+ return allowed_units
61+
62 def configure_db(hostname,
63 database,
64 username):
65@@ -81,12 +104,17 @@
66 password = configure_db(settings['hostname'],
67 settings['database'],
68 settings['username'])
69+ allowed_units = " ".join(unit_sorted(get_allowed_units(
70+ settings['database'],
71+ settings['username'])))
72 if not cluster.is_clustered():
73 utils.relation_set(db_host=local_hostname,
74- password=password)
75+ password=password,
76+ allowed_units=allowed_units)
77 else:
78 utils.relation_set(db_host=utils.config_get("vip"),
79- password=password)
80+ password=password,
81+ allowed_units=allowed_units)
82
83 else:
84 # Process multiple database setup requests.
85@@ -115,12 +143,17 @@
86 databases[db] = {}
87 databases[db][x] = v
88 return_data = {}
89+ allowed_units = []
90 for db in databases:
91 if singleset.issubset(databases[db]):
92 return_data['_'.join([db, 'password'])] = \
93 configure_db(databases[db]['hostname'],
94 databases[db]['database'],
95 databases[db]['username'])
96+ return_data['_'.join([db, 'allowed_units'])] = \
97+ " ".join(unit_sorted(get_allowed_units(
98+ databases[db]['database'],
99+ databases[db]['username'])))
100 if len(return_data) > 0:
101 utils.relation_set(**return_data)
102 if not cluster.is_clustered():

Subscribers

People subscribed via source and target branches

to all changes: