Merge lp:~gnuoy/charms/trusty/percona-cluster/sstpasswd2 into lp:~le-charmers/charms/trusty/percona-cluster/leadership-election

Proposed by Liam Young
Status: Rejected
Rejected by: Liam Young
Proposed branch: lp:~gnuoy/charms/trusty/percona-cluster/sstpasswd2
Merge into: lp:~le-charmers/charms/trusty/percona-cluster/leadership-election
Diff against target: 217 lines (+78/-10) (has conflicts)
3 files modified
hooks/charmhelpers/contrib/database/mysql.py (+21/-6)
hooks/percona_hooks.py (+54/-2)
hooks/percona_utils.py (+3/-2)
Text conflict in hooks/percona_hooks.py
To merge this branch: bzr merge lp:~gnuoy/charms/trusty/percona-cluster/sstpasswd2
Reviewer Review Type Date Requested Status
Edward Hope-Morley Pending
Review via email: mp+258979@code.launchpad.net

This proposal supersedes a proposal from 2015-05-12.

To post a comment you must log in.
Revision history for this message
Edward Hope-Morley (hopem) wrote : Posted in a previous version of this proposal

I'm surprised this has not given is more issue in production. So, unfortunately the way you are doing things here will break the case where no password is provided in config.yaml sst-passwd and is therefore auto-generated and shared on the peer relation. A better option might be to add a new param to get_mysl_password() e.g. create_if_none=False so that we check the peer rel and only create a new one if create_if_none if True which we would be the case only if we were the leader. FTR get_mysql_password() is also called from install() and config_changed() so will need protection there too.

review: Needs Fixing

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hooks/charmhelpers/contrib/database/mysql.py'
2--- hooks/charmhelpers/contrib/database/mysql.py 2015-05-11 10:23:34 +0000
3+++ hooks/charmhelpers/contrib/database/mysql.py 2015-05-13 10:25:03 +0000
4@@ -134,6 +134,14 @@
5 finally:
6 cursor.close()
7
8+ def wipe_disk_passwords(self):
9+ """Remove all passwords stored on disk"""
10+ dirname = os.path.dirname(self.root_passwd_file_template)
11+ path = os.path.join(dirname, '*.passwd')
12+ for f in glob.glob(path):
13+ log("Removing password file {}".format(f), level=DEBUG)
14+ os.unlink(f)
15+
16 def migrate_passwords_to_peer_relation(self, excludes=None):
17 """Migrate any passwords storage on disk to cluster peer relation."""
18 dirname = os.path.dirname(self.root_passwd_file_template)
19@@ -156,7 +164,7 @@
20 # NOTE cluster relation not yet ready - skip for now
21 pass
22
23- def get_mysql_password_on_disk(self, username=None, password=None):
24+ def get_mysql_password_on_disk(self, username=None, password=None, create_if_none=True):
25 """Retrieve, generate or store a mysql password for the provided
26 username on disk."""
27 if username:
28@@ -170,7 +178,7 @@
29 log("Using existing password file '%s'" % passwd_file, level=DEBUG)
30 with open(passwd_file, 'r') as passwd:
31 _password = passwd.read().strip()
32- else:
33+ elif create_if_none:
34 log("Generating new password file '%s'" % passwd_file, level=DEBUG)
35 if not os.path.isdir(os.path.dirname(passwd_file)):
36 # NOTE: need to ensure this is not mysql root dir (which needs
37@@ -207,7 +215,8 @@
38 for key in keys:
39 yield key
40
41- def get_mysql_password(self, username=None, password=None):
42+ def get_mysql_password(self, username=None, password=None,
43+ create_if_none=True):
44 """Retrieve, generate or store a mysql password for the provided
45 username using peer relation cluster."""
46 excludes = []
47@@ -227,12 +236,18 @@
48 # cluster relation is not yet started; use on-disk
49 _password = None
50
51- # If none available, generate new one
52+ # If none available, check if one is on disk, if not
53+ # get_mysql_password_on_disk will generate a new one if create_if_none
54+ # is true
55 if not _password:
56- _password = self.get_mysql_password_on_disk(username, password)
57+ _password = self.get_mysql_password_on_disk(
58+ username,
59+ password,
60+ create_if_none=create_if_none,
61+ )
62
63 # Put on wire if required
64- if self.migrate_passwd_to_peer_relation:
65+ if _password and self.migrate_passwd_to_peer_relation:
66 self.migrate_passwords_to_peer_relation(excludes=excludes)
67
68 return _password
69
70=== modified file 'hooks/charmhelpers/contrib/peerstorage/__init__.py'
71=== modified file 'hooks/charmhelpers/core/hookenv.py'
72=== modified file 'hooks/percona_hooks.py'
73--- hooks/percona_hooks.py 2015-05-11 10:23:34 +0000
74+++ hooks/percona_hooks.py 2015-05-13 10:25:03 +0000
75@@ -61,6 +61,13 @@
76 is_clustered,
77 oldest_peer,
78 peer_units,
79+<<<<<<< TREE
80+=======
81+ oldest_peer,
82+ is_elected_leader,
83+ is_clustered,
84+ is_leader,
85+>>>>>>> MERGE-SOURCE
86 )
87 from charmhelpers.payload.execd import execd_preinstall
88 from charmhelpers.contrib.network.ip import (
89@@ -94,6 +101,13 @@
90 add_source(config('source'), config('key'))
91
92 configure_mysql_root_password(config('root-password'))
93+<<<<<<< TREE
94+=======
95+ db_helper = get_db_helper(migrate_passwd_to_peer_relation=False)
96+ cfg_passwd = config('sst-password')
97+ mysql_password = db_helper.get_mysql_password(username='sstuser',
98+ password=cfg_passwd)
99+>>>>>>> MERGE-SOURCE
100 # Render base configuration (no cluster)
101 render_config()
102 apt_update(fatal=True)
103@@ -105,6 +119,15 @@
104 if not os.path.exists(os.path.dirname(MY_CNF)):
105 os.makedirs(os.path.dirname(MY_CNF))
106
107+<<<<<<< TREE
108+=======
109+ if not mysql_password:
110+ db_helper = get_db_helper(migrate_passwd_to_peer_relation=False)
111+ cfg_passwd = config('sst-password')
112+ mysql_password = db_helper.get_mysql_password(username='sstuser',
113+ password=cfg_passwd)
114+
115+>>>>>>> MERGE-SOURCE
116 context = {
117 'cluster_name': 'juju_cluster',
118 'private_address': get_host_ip(),
119@@ -141,7 +164,9 @@
120 clustered = len(hosts) > 1
121 pre_hash = file_hash(MY_CNF)
122 render_config(clustered, hosts)
123+ db_helper = get_db_helper()
124 if file_hash(MY_CNF) != pre_hash:
125+<<<<<<< TREE
126 try:
127 # NOTE(jamespage): try with leadership election
128 if clustered and not is_leader() and not seeded():
129@@ -162,6 +187,18 @@
130 # Restart with new configuration
131 service_restart('mysql')
132
133+=======
134+ oldest = oldest_peer(peer_units())
135+ if clustered and not oldest and not seeded():
136+ # Bootstrap node into seeded cluster
137+ service_restart('mysql')
138+ mark_seeded()
139+ # Bootstrapping from existing cluster invalidates passwords
140+ db_helper.wipe_disk_passwords()
141+ elif not clustered:
142+ # Restart with new configuration
143+ service_restart('mysql')
144+>>>>>>> MERGE-SOURCE
145 # Notify any changes to the access network
146 for r_id in relation_ids('shared-db'):
147 for unit in related_units(r_id):
148@@ -210,8 +247,15 @@
149 @hooks.hook('db-relation-changed')
150 @hooks.hook('db-admin-relation-changed')
151 def db_changed(relation_id=None, unit=None, admin=None):
152+<<<<<<< TREE
153 if not is_elected_leader(LEADER_RES):
154 log('Not leader of service, deferring db-changed to leader')
155+=======
156+ if not is_elected_leader(LEADER_RES):
157+ log('Service is peered, clearing db relation'
158+ ' as this service unit is not the leader')
159+ relation_clear(relation_id)
160+>>>>>>> MERGE-SOURCE
161 return
162
163 if is_clustered():
164@@ -280,10 +324,14 @@
165 # TODO: This could be a hook common between mysql and percona-cluster
166 @hooks.hook('shared-db-relation-changed')
167 def shared_db_changed(relation_id=None, unit=None):
168+<<<<<<< TREE
169 if not is_elected_leader(LEADER_RES):
170 # NOTE(jamespage): relation level data candidate
171 log('Service is peered, clearing shared-db relation'
172 ' as this service unit is not the leader')
173+=======
174+ if not is_elected_leader(LEADER_RES):
175+>>>>>>> MERGE-SOURCE
176 relation_clear(relation_id)
177 # Each unit needs to set the db information otherwise if the unit
178 # with the info dies the settings die with it Bug# 1355848
179@@ -417,13 +465,17 @@
180
181 resources = {'res_mysql_vip': res_mysql_vip,
182 'res_mysql_monitor': 'ocf:percona:mysql_monitor'}
183- db_helper = get_db_helper()
184+ if is_elected_leader(LEADER_RES):
185+ migrate_passwd=True
186+ else:
187+ migrate_passwd=False
188+ db_helper = get_db_helper(migrate_passwd_to_peer_relation=migrate_passwd)
189 cfg_passwd = config('sst-password')
190 sstpsswd = db_helper.get_mysql_password(username='sstuser',
191 password=cfg_passwd)
192 resource_params = {'res_mysql_vip': vip_params,
193 'res_mysql_monitor':
194- RES_MONITOR_PARAMS % {'sstpass': sstpsswd}}
195+ RES_MONITOR_PARAMS % {'sstpass': sstpsswd}}
196 groups = {'grp_percona_cluster': 'res_mysql_vip'}
197
198 clones = {'cl_mysql_monitor': 'res_mysql_monitor meta interleave=true'}
199
200=== modified file 'hooks/percona_utils.py'
201--- hooks/percona_utils.py 2015-03-09 14:02:03 +0000
202+++ hooks/percona_utils.py 2015-05-13 10:25:03 +0000
203@@ -135,11 +135,12 @@
204 "BY '{}'")
205
206
207-def get_db_helper():
208+def get_db_helper(migrate_passwd_to_peer_relation=True):
209 return MySQLHelper(rpasswdf_template='/var/lib/charm/%s/mysql.passwd' %
210 (service_name()),
211 upasswdf_template='/var/lib/charm/%s/mysql-{}.passwd' %
212- (service_name()))
213+ (service_name()),
214+ migrate_passwd_to_peer_relation=migrate_passwd_to_peer_relation)
215
216
217 def configure_sstuser(sst_password):

Subscribers

People subscribed via source and target branches