Merge lp:~hopem/charms/trusty/keystone/fix-db-migrate-race into lp:~openstack-charmers-archive/charms/trusty/keystone/next

Proposed by Edward Hope-Morley
Status: Merged
Merged at revision: 121
Proposed branch: lp:~hopem/charms/trusty/keystone/fix-db-migrate-race
Merge into: lp:~openstack-charmers-archive/charms/trusty/keystone/next
Diff against target: 334 lines (+84/-33)
3 files modified
hooks/keystone_hooks.py (+29/-23)
hooks/keystone_utils.py (+28/-2)
unit_tests/test_keystone_hooks.py (+27/-8)
To merge this branch: bzr merge lp:~hopem/charms/trusty/keystone/fix-db-migrate-race
Reviewer Review Type Date Requested Status
Liam Young (community) Approve
Review via email: mp+249904@code.launchpad.net
To post a comment you must log in.
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #2042 keystone-next for hopem mp249904
    LINT OK: passed

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #1832 keystone-next for hopem mp249904
    UNIT OK: passed

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #1980 keystone-next for hopem mp249904
    AMULET OK: passed

Build: http://10.245.162.77:8080/job/charm_amulet_test/1980/

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/keystone_hooks.py'
2--- hooks/keystone_hooks.py 2015-02-16 13:35:14 +0000
3+++ hooks/keystone_hooks.py 2015-02-17 00:12:48 +0000
4@@ -4,7 +4,6 @@
5 import os
6 import stat
7 import sys
8-import time
9
10 from subprocess import check_call
11
12@@ -72,6 +71,7 @@
13 is_ssl_cert_master,
14 is_db_ready,
15 clear_ssl_synced_units,
16+ is_db_initialised,
17 )
18
19 from charmhelpers.contrib.hahelpers.cluster import (
20@@ -198,17 +198,18 @@
21 level=INFO)
22 return
23
24- try:
25- migrate_database()
26- except Exception as exc:
27- log("Database initialisation failed (%s) - db not ready?" % (exc),
28- level=WARNING)
29- else:
30+ if not is_db_initialised():
31+ log("Database not yet initialised - deferring identity-relation "
32+ "updates", level=INFO)
33+ return
34+
35+ if is_elected_leader(CLUSTER_RES):
36 ensure_initial_admin(config)
37- log('Firing identity_changed hook for all related services.')
38- for rid in relation_ids('identity-service'):
39- for unit in related_units(rid):
40- identity_changed(relation_id=rid, remote_unit=unit)
41+
42+ log('Firing identity_changed hook for all related services.')
43+ for rid in relation_ids('identity-service'):
44+ for unit in related_units(rid):
45+ identity_changed(relation_id=rid, remote_unit=unit)
46
47
48 @synchronize_ca_if_changed(force=True)
49@@ -233,8 +234,10 @@
50 level=INFO)
51 return
52
53+ migrate_database()
54+
55 # Ensure any existing service entries are updated in the
56- # new database backend
57+ # new database backend. Also avoid duplicate db ready check.
58 update_all_identity_relation_units(check_db_ready=False)
59
60
61@@ -247,9 +250,15 @@
62 else:
63 CONFIGS.write(KEYSTONE_CONF)
64 if is_elected_leader(CLUSTER_RES):
65+ if not is_db_ready(use_current_context=True):
66+ log('Allowed_units list provided and this unit not present',
67+ level=INFO)
68+ return
69+
70+ migrate_database()
71 # Ensure any existing service entries are updated in the
72- # new database backend
73- update_all_identity_relation_units()
74+ # new database backend. Also avoid duplicate db ready check.
75+ update_all_identity_relation_units(check_db_ready=False)
76
77
78 @hooks.hook('identity-service-relation-changed')
79@@ -265,6 +274,11 @@
80 "ready - deferring until db ready", level=WARNING)
81 return
82
83+ if not is_db_initialised():
84+ log("Database not yet initialised - deferring identity-relation "
85+ "updates", level=INFO)
86+ return
87+
88 add_service_to_keystone(relation_id, remote_unit)
89 settings = relation_get(rid=relation_id, unit=remote_unit)
90 service = settings.get('service', None)
91@@ -394,7 +408,7 @@
92 # NOTE(jamespage) re-echo passwords for peer storage
93 echo_whitelist, overrides = \
94 apply_echo_filters(settings, ['_passwd', 'identity-service:',
95- 'ssl-cert-master'])
96+ 'ssl-cert-master', 'db-initialised'])
97 log("Peer echo overrides: %s" % (overrides), level=DEBUG)
98 relation_set(**overrides)
99 if echo_whitelist:
100@@ -487,15 +501,8 @@
101
102 clustered = relation_get('clustered')
103 if clustered and is_elected_leader(CLUSTER_RES):
104- if not is_db_ready():
105- log('Allowed_units list provided and this unit not present',
106- level=INFO)
107- return
108-
109- ensure_initial_admin(config)
110 log('Cluster configured, notifying other services and updating '
111 'keystone endpoint configuration')
112-
113 update_all_identity_relation_units()
114
115
116@@ -546,7 +553,6 @@
117 if is_elected_leader(CLUSTER_RES):
118 log('Cluster leader - ensuring endpoint configuration is up to '
119 'date', level=DEBUG)
120- time.sleep(10)
121 update_all_identity_relation_units()
122
123
124
125=== modified file 'hooks/keystone_utils.py'
126--- hooks/keystone_utils.py 2015-02-16 14:48:02 +0000
127+++ hooks/keystone_utils.py 2015-02-17 00:12:48 +0000
128@@ -314,7 +314,32 @@
129 configs.write_all()
130
131 if is_elected_leader(CLUSTER_RES):
132- migrate_database()
133+ if is_db_ready():
134+ migrate_database()
135+ else:
136+ log("Database not ready - deferring to shared-db relation",
137+ level=INFO)
138+ return
139+
140+
141+def set_db_initialised():
142+ for rid in relation_ids('cluster'):
143+ relation_set(relation_settings={'db-initialised': 'True'},
144+ relation_id=rid)
145+
146+
147+def is_db_initialised():
148+ for rid in relation_ids('cluster'):
149+ units = related_units(rid) + [local_unit()]
150+ for unit in units:
151+ db_initialised = relation_get(attribute='db-initialised',
152+ unit=unit, rid=rid)
153+ if db_initialised:
154+ log("Database is initialised", level=DEBUG)
155+ return True
156+
157+ log("Database is NOT initialised", level=DEBUG)
158+ return False
159
160
161 def migrate_database():
162@@ -328,10 +353,11 @@
163 subprocess.check_output(cmd)
164 service_start('keystone')
165 time.sleep(10)
166-
167+ set_db_initialised()
168
169 # OLD
170
171+
172 def get_local_endpoint():
173 """Returns the URL for the local end-point bypassing haproxy/ssl"""
174 if config('prefer-ipv6'):
175
176=== modified file 'unit_tests/test_keystone_hooks.py'
177--- unit_tests/test_keystone_hooks.py 2015-02-05 17:48:25 +0000
178+++ unit_tests/test_keystone_hooks.py 2015-02-17 00:12:48 +0000
179@@ -63,7 +63,6 @@
180 'execd_preinstall',
181 'mkdir',
182 'os',
183- 'time',
184 # ip
185 'get_iface_for_address',
186 'get_netmask_for_address',
187@@ -203,6 +202,7 @@
188 configs.write = MagicMock()
189 hooks.pgsql_db_changed()
190
191+ @patch.object(hooks, 'is_db_initialised')
192 @patch.object(hooks, 'is_db_ready')
193 @patch('keystone_utils.log')
194 @patch('keystone_utils.ensure_ssl_cert_master')
195@@ -210,7 +210,9 @@
196 @patch.object(hooks, 'identity_changed')
197 def test_db_changed_allowed(self, identity_changed, configs,
198 mock_ensure_ssl_cert_master,
199- mock_log, mock_is_db_ready):
200+ mock_log, mock_is_db_ready,
201+ mock_is_db_initialised):
202+ mock_is_db_initialised.return_value = True
203 mock_is_db_ready.return_value = True
204 mock_ensure_ssl_cert_master.return_value = False
205 self.relation_ids.return_value = ['identity-service:0']
206@@ -247,12 +249,14 @@
207
208 @patch('keystone_utils.log')
209 @patch('keystone_utils.ensure_ssl_cert_master')
210+ @patch.object(hooks, 'is_db_initialised')
211 @patch.object(hooks, 'is_db_ready')
212 @patch.object(hooks, 'CONFIGS')
213 @patch.object(hooks, 'identity_changed')
214 def test_postgresql_db_changed(self, identity_changed, configs,
215- mock_is_db_ready,
216+ mock_is_db_ready, mock_is_db_initialised,
217 mock_ensure_ssl_cert_master, mock_log):
218+ mock_is_db_initialised.return_value = True
219 mock_is_db_ready.return_value = True
220 mock_ensure_ssl_cert_master.return_value = False
221 self.relation_ids.return_value = ['identity-service:0']
222@@ -269,6 +273,7 @@
223
224 @patch('keystone_utils.log')
225 @patch('keystone_utils.ensure_ssl_cert_master')
226+ @patch.object(hooks, 'is_db_initialised')
227 @patch.object(hooks, 'is_db_ready')
228 @patch.object(hooks, 'peer_units')
229 @patch.object(hooks, 'ensure_permissions')
230@@ -283,8 +288,9 @@
231 self, configure_https, identity_changed,
232 configs, get_homedir, ensure_user, cluster_joined,
233 admin_relation_changed, ensure_permissions, mock_peer_units,
234- mock_is_db_ready,
235+ mock_is_db_ready, mock_is_db_initialised,
236 mock_ensure_ssl_cert_master, mock_log):
237+ mock_is_db_initialised.return_value = True
238 mock_is_db_ready.return_value = True
239 self.openstack_upgrade_available.return_value = False
240 self.is_elected_leader.return_value = True
241@@ -302,7 +308,6 @@
242 configure_https.assert_called_with()
243 self.assertTrue(configs.write_all.called)
244
245- self.migrate_database.assert_called_with()
246 self.assertTrue(self.ensure_initial_admin.called)
247 self.log.assert_called_with(
248 'Firing identity_changed hook for all related services.')
249@@ -343,6 +348,7 @@
250
251 @patch('keystone_utils.log')
252 @patch('keystone_utils.ensure_ssl_cert_master')
253+ @patch.object(hooks, 'is_db_initialised')
254 @patch.object(hooks, 'is_db_ready')
255 @patch.object(hooks, 'peer_units')
256 @patch.object(hooks, 'ensure_permissions')
257@@ -361,9 +367,11 @@
258 ensure_permissions,
259 mock_peer_units,
260 mock_is_db_ready,
261+ mock_is_db_initialised,
262 mock_ensure_ssl_cert_master,
263 mock_log):
264 mock_is_db_ready.return_value = True
265+ mock_is_db_initialised.return_value = True
266 self.openstack_upgrade_available.return_value = True
267 self.is_elected_leader.return_value = True
268 # avoid having to mock syncer
269@@ -382,7 +390,6 @@
270 configure_https.assert_called_with()
271 self.assertTrue(configs.write_all.called)
272
273- self.migrate_database.assert_called_with()
274 self.assertTrue(self.ensure_initial_admin.called)
275 self.log.assert_called_with(
276 'Firing identity_changed hook for all related services.')
277@@ -391,6 +398,7 @@
278 remote_unit='unit/0')
279 admin_relation_changed.assert_called_with('identity-service:0')
280
281+ @patch.object(hooks, 'is_db_initialised')
282 @patch.object(hooks, 'is_db_ready')
283 @patch('keystone_utils.log')
284 @patch('keystone_utils.ensure_ssl_cert_master')
285@@ -398,7 +406,9 @@
286 @patch.object(hooks, 'send_notifications')
287 def test_identity_changed_leader(self, mock_send_notifications,
288 mock_hashlib, mock_ensure_ssl_cert_master,
289- mock_log, mock_is_db_ready):
290+ mock_log, mock_is_db_ready,
291+ mock_is_db_initialised):
292+ mock_is_db_initialised.return_value = True
293 mock_is_db_ready.return_value = True
294 mock_ensure_ssl_cert_master.return_value = False
295 hooks.identity_changed(
296@@ -557,13 +567,16 @@
297 @patch('keystone_utils.log')
298 @patch('keystone_utils.ensure_ssl_cert_master')
299 @patch.object(hooks, 'is_db_ready')
300+ @patch.object(hooks, 'is_db_initialised')
301 @patch.object(hooks, 'identity_changed')
302 @patch.object(hooks, 'CONFIGS')
303 def test_ha_relation_changed_clustered_leader(self, configs,
304 identity_changed,
305+ mock_is_db_initialised,
306 mock_is_db_ready,
307 mock_ensure_ssl_cert_master,
308 mock_log):
309+ mock_is_db_initialised.return_value = True
310 mock_is_db_ready.return_value = True
311 mock_ensure_ssl_cert_master.return_value = False
312 self.relation_get.return_value = True
313@@ -610,6 +623,8 @@
314 cmd = ['a2dissite', 'openstack_https_frontend']
315 self.check_call.assert_called_with(cmd)
316
317+ @patch.object(hooks, 'is_db_ready')
318+ @patch.object(hooks, 'is_db_initialised')
319 @patch('keystone_utils.log')
320 @patch('keystone_utils.relation_ids')
321 @patch('keystone_utils.is_elected_leader')
322@@ -623,7 +638,11 @@
323 mock_ensure_ssl_cert_master,
324 mock_is_elected_leader,
325 mock_relation_ids,
326- mock_log):
327+ mock_log,
328+ mock_is_db_ready,
329+ mock_is_db_initialised):
330+ mock_is_db_initialised.return_value = True
331+ mock_is_db_ready.return_value = True
332 mock_is_elected_leader.return_value = False
333 mock_relation_ids.return_value = []
334 mock_ensure_ssl_cert_master.return_value = True

Subscribers

People subscribed via source and target branches