Merge lp:~hopem/charms/trusty/keystone/stable-backport-lp1415579 into lp:~openstack-charmers-archive/charms/trusty/keystone/trunk
- Trusty Tahr (14.04)
- stable-backport-lp1415579
- Merge into trunk
Proposed by
Edward Hope-Morley
Status: | Merged |
---|---|
Merged at revision: | 117 |
Proposed branch: | lp:~hopem/charms/trusty/keystone/stable-backport-lp1415579 |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/keystone/trunk |
Diff against target: |
588 lines (+270/-102) 5 files modified
hooks/charmhelpers/contrib/unison/__init__.py (+6/-4) hooks/charmhelpers/core/sysctl.py (+11/-5) hooks/keystone_hooks.py (+36/-15) hooks/keystone_utils.py (+78/-36) unit_tests/test_keystone_utils.py (+139/-42) |
To merge this branch: | bzr merge lp:~hopem/charms/trusty/keystone/stable-backport-lp1415579 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Page | Approve | ||
Review via email: mp+248894@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : | # |
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #1609 keystone for hopem mp248894
UNIT OK: passed
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #1801 keystone for hopem mp248894
AMULET OK: passed
Build: http://
Revision history for this message
James Page (james-page) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'hooks/charmhelpers/contrib/unison/__init__.py' |
2 | --- hooks/charmhelpers/contrib/unison/__init__.py 2015-01-26 09:44:47 +0000 |
3 | +++ hooks/charmhelpers/contrib/unison/__init__.py 2015-02-06 12:31:31 +0000 |
4 | @@ -73,6 +73,7 @@ |
5 | relation_set, |
6 | relation_get, |
7 | unit_private_ip, |
8 | + INFO, |
9 | ERROR, |
10 | ) |
11 | |
12 | @@ -86,7 +87,7 @@ |
13 | user = pwd.getpwnam(user) |
14 | return user.pw_dir |
15 | except KeyError: |
16 | - log('Could not get homedir for user %s: user exists?', ERROR) |
17 | + log('Could not get homedir for user %s: user exists?' % (user), ERROR) |
18 | raise Exception |
19 | |
20 | |
21 | @@ -233,14 +234,15 @@ |
22 | rid=r_id, unit=unit) |
23 | |
24 | if not authed_hosts: |
25 | - log('Peer %s has not authorized *any* hosts yet, skipping.') |
26 | + log('Peer %s has not authorized *any* hosts yet, skipping.' % |
27 | + (unit), level=INFO) |
28 | continue |
29 | |
30 | if unit_private_ip() in authed_hosts.split(':'): |
31 | hosts.append(private_addr) |
32 | else: |
33 | - log('Peer %s has not authorized *this* host yet, skipping.') |
34 | - |
35 | + log('Peer %s has not authorized *this* host yet, skipping.' % |
36 | + (unit), level=INFO) |
37 | return hosts |
38 | |
39 | |
40 | |
41 | === modified file 'hooks/charmhelpers/core/sysctl.py' |
42 | --- hooks/charmhelpers/core/sysctl.py 2015-01-26 09:44:47 +0000 |
43 | +++ hooks/charmhelpers/core/sysctl.py 2015-02-06 12:31:31 +0000 |
44 | @@ -26,25 +26,31 @@ |
45 | from charmhelpers.core.hookenv import ( |
46 | log, |
47 | DEBUG, |
48 | + ERROR, |
49 | ) |
50 | |
51 | |
52 | def create(sysctl_dict, sysctl_file): |
53 | """Creates a sysctl.conf file from a YAML associative array |
54 | |
55 | - :param sysctl_dict: a dict of sysctl options eg { 'kernel.max_pid': 1337 } |
56 | - :type sysctl_dict: dict |
57 | + :param sysctl_dict: a YAML-formatted string of sysctl options eg "{ 'kernel.max_pid': 1337 }" |
58 | + :type sysctl_dict: str |
59 | :param sysctl_file: path to the sysctl file to be saved |
60 | :type sysctl_file: str or unicode |
61 | :returns: None |
62 | """ |
63 | - sysctl_dict = yaml.load(sysctl_dict) |
64 | + try: |
65 | + sysctl_dict_parsed = yaml.safe_load(sysctl_dict) |
66 | + except yaml.YAMLError: |
67 | + log("Error parsing YAML sysctl_dict: {}".format(sysctl_dict), |
68 | + level=ERROR) |
69 | + return |
70 | |
71 | with open(sysctl_file, "w") as fd: |
72 | - for key, value in sysctl_dict.items(): |
73 | + for key, value in sysctl_dict_parsed.items(): |
74 | fd.write("{}={}\n".format(key, value)) |
75 | |
76 | - log("Updating sysctl_file: %s values: %s" % (sysctl_file, sysctl_dict), |
77 | + log("Updating sysctl_file: %s values: %s" % (sysctl_file, sysctl_dict_parsed), |
78 | level=DEBUG) |
79 | |
80 | check_call(["sysctl", "-p", sysctl_file]) |
81 | |
82 | === modified file 'hooks/keystone_hooks.py' |
83 | --- hooks/keystone_hooks.py 2015-01-27 22:21:37 +0000 |
84 | +++ hooks/keystone_hooks.py 2015-02-06 12:31:31 +0000 |
85 | @@ -67,6 +67,7 @@ |
86 | is_str_true, |
87 | is_ssl_cert_master, |
88 | is_db_ready, |
89 | + clear_ssl_synced_units, |
90 | ) |
91 | |
92 | from charmhelpers.contrib.hahelpers.cluster import ( |
93 | @@ -150,11 +151,8 @@ |
94 | admin_relation_changed(rid) |
95 | |
96 | # Ensure sync request is sent out (needed for upgrade to ssl from non-ssl) |
97 | - settings = {} |
98 | - append_ssl_sync_request(settings) |
99 | - if settings: |
100 | - for rid in relation_ids('cluster'): |
101 | - relation_set(relation_id=rid, relation_settings=settings) |
102 | + send_ssl_sync_request() |
103 | + |
104 | for r_id in relation_ids('ha'): |
105 | ha_joined(relation_id=r_id) |
106 | |
107 | @@ -283,15 +281,39 @@ |
108 | send_notifications(notifications) |
109 | |
110 | |
111 | -def append_ssl_sync_request(settings): |
112 | - """Add request to be synced to relation settings. |
113 | - |
114 | - This will be consumed by cluster-relation-changed ssl master. |
115 | +def send_ssl_sync_request(): |
116 | + """Set sync request on cluster relation. |
117 | + |
118 | + Value set equals number of ssl configs currently enabled so that if they |
119 | + change, we ensure that certs are synced. This setting is consumed by |
120 | + cluster-relation-changed ssl master. We also clear the 'synced' set to |
121 | + guarantee that a sync will occur. |
122 | + |
123 | + Note the we do nothing if the setting is already applied. |
124 | """ |
125 | - if (is_str_true(config('use-https')) or |
126 | - is_str_true(config('https-service-endpoints'))): |
127 | - unit = local_unit().replace('/', '-') |
128 | - settings['ssl-sync-required-%s' % (unit)] = '1' |
129 | + unit = local_unit().replace('/', '-') |
130 | + count = 0 |
131 | + if is_str_true(config('use-https')): |
132 | + count += 1 |
133 | + |
134 | + if is_str_true(config('https-service-endpoints')): |
135 | + count += 2 |
136 | + |
137 | + if count: |
138 | + key = 'ssl-sync-required-%s' % (unit) |
139 | + settings = {key: count} |
140 | + prev = 0 |
141 | + rid = None |
142 | + for rid in relation_ids('cluster'): |
143 | + for unit in related_units(rid): |
144 | + _prev = relation_get(rid=rid, unit=unit, attribute=key) or 0 |
145 | + if _prev and _prev > prev: |
146 | + prev = _prev |
147 | + |
148 | + if rid and prev < count: |
149 | + clear_ssl_synced_units() |
150 | + log("Setting %s=%s" % (key, count), level=DEBUG) |
151 | + relation_set(relation_id=rid, relation_settings=settings) |
152 | |
153 | |
154 | @hooks.hook('cluster-relation-joined') |
155 | @@ -314,9 +336,8 @@ |
156 | private_addr = get_ipv6_addr(exc_list=[config('vip')])[0] |
157 | settings['private-address'] = private_addr |
158 | |
159 | - append_ssl_sync_request(settings) |
160 | - |
161 | relation_set(relation_settings=settings) |
162 | + send_ssl_sync_request() |
163 | |
164 | |
165 | def apply_echo_filters(settings, echo_whitelist): |
166 | |
167 | === modified file 'hooks/keystone_utils.py' |
168 | --- hooks/keystone_utils.py 2015-02-02 13:52:05 +0000 |
169 | +++ hooks/keystone_utils.py 2015-02-06 12:31:31 +0000 |
170 | @@ -21,7 +21,6 @@ |
171 | determine_api_port, |
172 | https, |
173 | peer_units, |
174 | - oldest_peer, |
175 | ) |
176 | |
177 | from charmhelpers.contrib.openstack import context, templating |
178 | @@ -764,14 +763,27 @@ |
179 | def unison_sync(paths_to_sync): |
180 | """Do unison sync and retry a few times if it fails since peers may not be |
181 | ready for sync. |
182 | + |
183 | + Returns list of synced units or None if one or more peers was not synced. |
184 | """ |
185 | log('Synchronizing CA (%s) to all peers.' % (', '.join(paths_to_sync)), |
186 | level=INFO) |
187 | keystone_gid = grp.getgrnam('keystone').gr_gid |
188 | + |
189 | + # NOTE(dosaboy): This will sync to all peers who have already provided |
190 | + # their ssh keys. If any existing peers have not provided their keys yet, |
191 | + # they will be silently ignored. |
192 | unison.sync_to_peers(peer_interface='cluster', paths=paths_to_sync, |
193 | user=SSH_USER, verbose=True, gid=keystone_gid, |
194 | fatal=True) |
195 | |
196 | + synced_units = peer_units() |
197 | + if len(unison.collect_authed_hosts('cluster')) != len(synced_units): |
198 | + log("Not all peer units synced due to missing public keys", level=INFO) |
199 | + return None |
200 | + else: |
201 | + return synced_units |
202 | + |
203 | |
204 | def get_ssl_sync_request_units(): |
205 | """Get list of units that have requested to be synced. |
206 | @@ -791,14 +803,22 @@ |
207 | return units |
208 | |
209 | |
210 | -def is_ssl_cert_master(): |
211 | +def is_ssl_cert_master(votes=None): |
212 | """Return True if this unit is ssl cert master.""" |
213 | master = None |
214 | for rid in relation_ids('cluster'): |
215 | master = relation_get(attribute='ssl-cert-master', rid=rid, |
216 | unit=local_unit()) |
217 | |
218 | - return master == local_unit() |
219 | + if master == local_unit(): |
220 | + votes = votes or get_ssl_cert_master_votes() |
221 | + if not peer_units() or (len(votes) == 1 and master in votes): |
222 | + return True |
223 | + |
224 | + log("Did not get consensus from peers on who is ssl-cert-master " |
225 | + "(%s)" % (votes), level=INFO) |
226 | + |
227 | + return False |
228 | |
229 | |
230 | def is_ssl_enabled(): |
231 | @@ -812,7 +832,21 @@ |
232 | return True |
233 | |
234 | |
235 | -def ensure_ssl_cert_master(use_oldest_peer=False): |
236 | +def get_ssl_cert_master_votes(): |
237 | + """Returns a list of unique votes.""" |
238 | + votes = [] |
239 | + # Gather election results from peers. These will need to be consistent. |
240 | + for rid in relation_ids('cluster'): |
241 | + for unit in related_units(rid): |
242 | + m = relation_get(rid=rid, unit=unit, |
243 | + attribute='ssl-cert-master') |
244 | + if m is not None: |
245 | + votes.append(m) |
246 | + |
247 | + return list(set(votes)) |
248 | + |
249 | + |
250 | +def ensure_ssl_cert_master(): |
251 | """Ensure that an ssl cert master has been elected. |
252 | |
253 | Normally the cluster leader will take control but we allow for this to be |
254 | @@ -822,31 +856,19 @@ |
255 | if not is_ssl_enabled(): |
256 | return False |
257 | |
258 | - elect = False |
259 | - peers = peer_units() |
260 | master_override = False |
261 | - if use_oldest_peer: |
262 | - elect = oldest_peer(peers) |
263 | - else: |
264 | - elect = is_elected_leader(CLUSTER_RES) |
265 | + elect = is_elected_leader(CLUSTER_RES) |
266 | |
267 | # If no peers we allow this unit to elect itsef as master and do |
268 | # sync immediately. |
269 | - if not peers and not is_ssl_cert_master(): |
270 | + if not peer_units(): |
271 | elect = True |
272 | master_override = True |
273 | |
274 | if elect: |
275 | - masters = [] |
276 | - for rid in relation_ids('cluster'): |
277 | - for unit in related_units(rid): |
278 | - m = relation_get(rid=rid, unit=unit, |
279 | - attribute='ssl-cert-master') |
280 | - if m is not None: |
281 | - masters.append(m) |
282 | - |
283 | + votes = get_ssl_cert_master_votes() |
284 | # We expect all peers to echo this setting |
285 | - if not masters or 'unknown' in masters: |
286 | + if not votes or 'unknown' in votes: |
287 | log("Notifying peers this unit is ssl-cert-master", level=INFO) |
288 | for rid in relation_ids('cluster'): |
289 | settings = {'ssl-cert-master': local_unit()} |
290 | @@ -855,10 +877,11 @@ |
291 | # Return now and wait for cluster-relation-changed (peer_echo) for |
292 | # sync. |
293 | return master_override |
294 | - elif len(set(masters)) != 1 and local_unit() not in masters: |
295 | - log("Did not get consensus from peers on who is ssl-cert-master " |
296 | - "(%s) - waiting for current master to release before " |
297 | - "self-electing" % (masters), level=INFO) |
298 | + elif not is_ssl_cert_master(votes): |
299 | + if not master_override: |
300 | + log("Conscensus not reached - current master will need to " |
301 | + "release", level=INFO) |
302 | + |
303 | return master_override |
304 | |
305 | if not is_ssl_cert_master(): |
306 | @@ -887,15 +910,18 @@ |
307 | log("Syncing all endpoint certs since https-service-endpoints=True", |
308 | level=DEBUG) |
309 | paths_to_sync.append(SSL_DIR) |
310 | - paths_to_sync.append(APACHE_SSL_DIR) |
311 | paths_to_sync.append(CA_CERT_PATH) |
312 | - elif is_str_true(config('use-https')): |
313 | + |
314 | + if is_str_true(config('use-https')): |
315 | log("Syncing keystone-endpoint certs since use-https=True", |
316 | level=DEBUG) |
317 | paths_to_sync.append(SSL_DIR) |
318 | paths_to_sync.append(APACHE_SSL_DIR) |
319 | paths_to_sync.append(CA_CERT_PATH) |
320 | |
321 | + # Ensure unique |
322 | + paths_to_sync = list(set(paths_to_sync)) |
323 | + |
324 | if not paths_to_sync: |
325 | log("Nothing to sync - skipping", level=DEBUG) |
326 | return {} |
327 | @@ -908,8 +934,7 @@ |
328 | create_peer_service_actions('restart', ['apache2']) |
329 | create_peer_actions(['update-ca-certificates']) |
330 | |
331 | - # Format here needs to match that used when peers request sync |
332 | - synced_units = [unit.replace('/', '-') for unit in peer_units()] |
333 | + cluster_rel_settings = {} |
334 | |
335 | retries = 3 |
336 | while True: |
337 | @@ -918,7 +943,12 @@ |
338 | update_hash_from_path(hash1, path) |
339 | |
340 | try: |
341 | - unison_sync(paths_to_sync) |
342 | + synced_units = unison_sync(paths_to_sync) |
343 | + if synced_units: |
344 | + # Format here needs to match that used when peers request sync |
345 | + synced_units = [u.replace('/', '-') for u in synced_units] |
346 | + cluster_rel_settings['ssl-synced-units'] = \ |
347 | + json.dumps(synced_units) |
348 | except: |
349 | if fatal: |
350 | raise |
351 | @@ -947,10 +977,22 @@ |
352 | hash = hash1.hexdigest() |
353 | log("Sending restart-services-trigger=%s to all peers" % (hash), |
354 | level=DEBUG) |
355 | + cluster_rel_settings['restart-services-trigger'] = hash |
356 | |
357 | log("Sync complete", level=DEBUG) |
358 | - return {'restart-services-trigger': hash, |
359 | - 'ssl-synced-units': json.dumps(synced_units)} |
360 | + return cluster_rel_settings |
361 | + |
362 | + |
363 | +def clear_ssl_synced_units(): |
364 | + """Clear the 'synced' units record on the cluster relation. |
365 | + |
366 | + If new unit sync reauests are set this will ensure that a sync occurs when |
367 | + the sync master receives the requests. |
368 | + """ |
369 | + log("Clearing ssl sync units", level=DEBUG) |
370 | + for rid in relation_ids('cluster'): |
371 | + relation_set(relation_id=rid, |
372 | + relation_settings={'ssl-synced-units': None}) |
373 | |
374 | |
375 | def update_hash_from_path(hash, path, recurse_depth=10): |
376 | @@ -1058,11 +1100,11 @@ |
377 | '%s' % SSL_DIR]) |
378 | subprocess.check_output(['chmod', '-R', 'g+rwx', '%s' % SSL_DIR]) |
379 | |
380 | - # Ensure a master has been elected and prefer this unit. Note that we |
381 | - # prefer oldest peer as predicate since this action i normally only |
382 | - # performed once at deploy time when the oldest peer should be the |
383 | - # first to be ready. |
384 | - ensure_ssl_cert_master(use_oldest_peer=True) |
385 | + # Ensure a master is elected. This should cover the following cases: |
386 | + # * single unit == 'oldest' unit is elected as master |
387 | + # * multi unit + not clustered == 'oldest' unit is elcted as master |
388 | + # * multi unit + clustered == cluster leader is elected as master |
389 | + ensure_ssl_cert_master() |
390 | |
391 | ssl.CA_SINGLETON.append(ca) |
392 | |
393 | |
394 | === modified file 'unit_tests/test_keystone_utils.py' |
395 | --- unit_tests/test_keystone_utils.py 2015-02-02 13:52:05 +0000 |
396 | +++ unit_tests/test_keystone_utils.py 2015-02-06 12:31:31 +0000 |
397 | @@ -28,6 +28,7 @@ |
398 | 'grant_role', |
399 | 'configure_installation_source', |
400 | 'is_elected_leader', |
401 | + 'is_ssl_cert_master', |
402 | 'https', |
403 | 'peer_store_and_set', |
404 | 'service_stop', |
405 | @@ -380,45 +381,141 @@ |
406 | self.assertTrue(utils.is_db_ready()) |
407 | |
408 | @patch.object(utils, 'peer_units') |
409 | - @patch.object(utils, 'is_elected_leader') |
410 | - @patch.object(utils, 'oldest_peer') |
411 | - @patch.object(utils, 'is_ssl_enabled') |
412 | - def test_ensure_ssl_cert_master(self, mock_is_str_true, mock_oldest_peer, |
413 | - mock_is_elected_leader, mock_peer_units): |
414 | - self.relation_ids.return_value = ['cluster:0'] |
415 | - self.local_unit.return_value = 'unit/0' |
416 | - |
417 | - mock_is_str_true.return_value = False |
418 | - self.assertFalse(utils.ensure_ssl_cert_master()) |
419 | - self.assertFalse(self.relation_set.called) |
420 | - |
421 | - mock_is_elected_leader.return_value = False |
422 | - self.assertFalse(utils.ensure_ssl_cert_master()) |
423 | - self.assertFalse(self.relation_set.called) |
424 | - |
425 | - mock_is_str_true.return_value = True |
426 | - mock_is_elected_leader.return_value = False |
427 | - mock_peer_units.return_value = ['unit/0'] |
428 | - self.assertFalse(utils.ensure_ssl_cert_master()) |
429 | - self.assertFalse(self.relation_set.called) |
430 | - |
431 | - mock_peer_units.return_value = [] |
432 | - self.assertTrue(utils.ensure_ssl_cert_master()) |
433 | - settings = {'ssl-cert-master': 'unit/0'} |
434 | - self.relation_set.assert_called_with(relation_id='cluster:0', |
435 | - relation_settings=settings) |
436 | - self.relation_set.reset_mock() |
437 | - |
438 | - self.assertTrue(utils.ensure_ssl_cert_master(use_oldest_peer=True)) |
439 | - settings = {'ssl-cert-master': 'unit/0'} |
440 | - self.relation_set.assert_called_with(relation_id='cluster:0', |
441 | - relation_settings=settings) |
442 | - self.relation_set.reset_mock() |
443 | - |
444 | - mock_peer_units.return_value = ['unit/0'] |
445 | - self.assertFalse(utils.ensure_ssl_cert_master()) |
446 | - self.assertFalse(utils.ensure_ssl_cert_master(use_oldest_peer=True)) |
447 | - settings = {'ssl-cert-master': 'unit/0'} |
448 | - self.relation_set.assert_called_with(relation_id='cluster:0', |
449 | - relation_settings=settings) |
450 | - self.relation_set.reset_mock() |
451 | + @patch.object(utils, 'is_ssl_enabled') |
452 | + def test_ensure_ssl_cert_master_no_ssl(self, mock_is_ssl_enabled, |
453 | + mock_peer_units): |
454 | + mock_is_ssl_enabled.return_value = False |
455 | + self.assertFalse(utils.ensure_ssl_cert_master()) |
456 | + self.assertFalse(self.relation_set.called) |
457 | + |
458 | + @patch.object(utils, 'peer_units') |
459 | + @patch.object(utils, 'is_ssl_enabled') |
460 | + def test_ensure_ssl_cert_master_ssl_no_peers(self, mock_is_ssl_enabled, |
461 | + mock_peer_units): |
462 | + def mock_rel_get(unit=None, **kwargs): |
463 | + return None |
464 | + |
465 | + self.relation_get.side_effect = mock_rel_get |
466 | + mock_is_ssl_enabled.return_value = True |
467 | + self.relation_ids.return_value = ['cluster:0'] |
468 | + self.local_unit.return_value = 'unit/0' |
469 | + self.related_units.return_value = [] |
470 | + mock_peer_units.return_value = [] |
471 | + # This should get ignored since we are overriding |
472 | + self.is_ssl_cert_master.return_value = False |
473 | + self.is_elected_leader.return_value = False |
474 | + self.assertTrue(utils.ensure_ssl_cert_master()) |
475 | + settings = {'ssl-cert-master': 'unit/0'} |
476 | + self.relation_set.assert_called_with(relation_id='cluster:0', |
477 | + relation_settings=settings) |
478 | + |
479 | + @patch.object(utils, 'peer_units') |
480 | + @patch.object(utils, 'is_ssl_enabled') |
481 | + def test_ensure_ssl_cert_master_ssl_master_no_peers(self, |
482 | + mock_is_ssl_enabled, |
483 | + mock_peer_units): |
484 | + def mock_rel_get(unit=None, **kwargs): |
485 | + if unit == 'unit/0': |
486 | + return 'unit/0' |
487 | + |
488 | + return None |
489 | + |
490 | + self.relation_get.side_effect = mock_rel_get |
491 | + mock_is_ssl_enabled.return_value = True |
492 | + self.relation_ids.return_value = ['cluster:0'] |
493 | + self.local_unit.return_value = 'unit/0' |
494 | + self.related_units.return_value = [] |
495 | + mock_peer_units.return_value = [] |
496 | + # This should get ignored since we are overriding |
497 | + self.is_ssl_cert_master.return_value = False |
498 | + self.is_elected_leader.return_value = False |
499 | + self.assertTrue(utils.ensure_ssl_cert_master()) |
500 | + settings = {'ssl-cert-master': 'unit/0'} |
501 | + self.relation_set.assert_called_with(relation_id='cluster:0', |
502 | + relation_settings=settings) |
503 | + |
504 | + @patch.object(utils, 'peer_units') |
505 | + @patch.object(utils, 'is_ssl_enabled') |
506 | + def test_ensure_ssl_cert_master_ssl_not_leader(self, mock_is_ssl_enabled, |
507 | + mock_peer_units): |
508 | + mock_is_ssl_enabled.return_value = True |
509 | + self.relation_ids.return_value = ['cluster:0'] |
510 | + self.local_unit.return_value = 'unit/0' |
511 | + mock_peer_units.return_value = ['unit/1'] |
512 | + self.is_ssl_cert_master.return_value = False |
513 | + self.is_elected_leader.return_value = False |
514 | + self.assertFalse(utils.ensure_ssl_cert_master()) |
515 | + self.assertFalse(self.relation_set.called) |
516 | + |
517 | + @patch.object(utils, 'peer_units') |
518 | + @patch.object(utils, 'is_ssl_enabled') |
519 | + def test_ensure_ssl_cert_master_is_leader_new_peer(self, |
520 | + mock_is_ssl_enabled, |
521 | + mock_peer_units): |
522 | + def mock_rel_get(unit=None, **kwargs): |
523 | + if unit == 'unit/0': |
524 | + return 'unit/0' |
525 | + |
526 | + return 'unknown' |
527 | + |
528 | + self.relation_get.side_effect = mock_rel_get |
529 | + mock_is_ssl_enabled.return_value = True |
530 | + self.relation_ids.return_value = ['cluster:0'] |
531 | + self.local_unit.return_value = 'unit/0' |
532 | + mock_peer_units.return_value = ['unit/1'] |
533 | + self.related_units.return_value = ['unit/1'] |
534 | + self.is_ssl_cert_master.return_value = False |
535 | + self.is_elected_leader.return_value = True |
536 | + self.assertFalse(utils.ensure_ssl_cert_master()) |
537 | + settings = {'ssl-cert-master': 'unit/0'} |
538 | + self.relation_set.assert_called_with(relation_id='cluster:0', |
539 | + relation_settings=settings) |
540 | + |
541 | + @patch.object(utils, 'peer_units') |
542 | + @patch.object(utils, 'is_ssl_enabled') |
543 | + def test_ensure_ssl_cert_master_is_leader_no_new_peer(self, |
544 | + mock_is_ssl_enabled, |
545 | + mock_peer_units): |
546 | + def mock_rel_get(unit=None, **kwargs): |
547 | + if unit == 'unit/0': |
548 | + return 'unit/0' |
549 | + |
550 | + return 'unit/0' |
551 | + |
552 | + self.relation_get.side_effect = mock_rel_get |
553 | + mock_is_ssl_enabled.return_value = True |
554 | + self.relation_ids.return_value = ['cluster:0'] |
555 | + self.local_unit.return_value = 'unit/0' |
556 | + mock_peer_units.return_value = ['unit/1'] |
557 | + self.related_units.return_value = ['unit/1'] |
558 | + self.is_ssl_cert_master.return_value = False |
559 | + self.is_elected_leader.return_value = True |
560 | + self.assertFalse(utils.ensure_ssl_cert_master()) |
561 | + self.assertFalse(self.relation_set.called) |
562 | + |
563 | + @patch.object(utils, 'peer_units') |
564 | + @patch.object(utils, 'is_ssl_enabled') |
565 | + def test_ensure_ssl_cert_master_is_leader_bad_votes(self, |
566 | + mock_is_ssl_enabled, |
567 | + mock_peer_units): |
568 | + counter = {0: 0} |
569 | + |
570 | + def mock_rel_get(unit=None, **kwargs): |
571 | + """Returns a mix of votes.""" |
572 | + if unit == 'unit/0': |
573 | + return 'unit/0' |
574 | + |
575 | + ret = 'unit/%d' % (counter[0]) |
576 | + counter[0] += 1 |
577 | + return ret |
578 | + |
579 | + self.relation_get.side_effect = mock_rel_get |
580 | + mock_is_ssl_enabled.return_value = True |
581 | + self.relation_ids.return_value = ['cluster:0'] |
582 | + self.local_unit.return_value = 'unit/0' |
583 | + mock_peer_units.return_value = ['unit/1'] |
584 | + self.related_units.return_value = ['unit/1'] |
585 | + self.is_ssl_cert_master.return_value = False |
586 | + self.is_elected_leader.return_value = True |
587 | + self.assertFalse(utils.ensure_ssl_cert_master()) |
588 | + self.assertFalse(self.relation_set.called) |
charm_lint_check #1781 keystone for hopem mp248894
LINT OK: passed
Build: http:// 10.245. 162.77: 8080/job/ charm_lint_ check/1781/