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 | 73 | relation_set, | 73 | relation_set, |
6 | 74 | relation_get, | 74 | relation_get, |
7 | 75 | unit_private_ip, | 75 | unit_private_ip, |
8 | 76 | INFO, | ||
9 | 76 | ERROR, | 77 | ERROR, |
10 | 77 | ) | 78 | ) |
11 | 78 | 79 | ||
12 | @@ -86,7 +87,7 @@ | |||
13 | 86 | user = pwd.getpwnam(user) | 87 | user = pwd.getpwnam(user) |
14 | 87 | return user.pw_dir | 88 | return user.pw_dir |
15 | 88 | except KeyError: | 89 | except KeyError: |
17 | 89 | log('Could not get homedir for user %s: user exists?', ERROR) | 90 | log('Could not get homedir for user %s: user exists?' % (user), ERROR) |
18 | 90 | raise Exception | 91 | raise Exception |
19 | 91 | 92 | ||
20 | 92 | 93 | ||
21 | @@ -233,14 +234,15 @@ | |||
22 | 233 | rid=r_id, unit=unit) | 234 | rid=r_id, unit=unit) |
23 | 234 | 235 | ||
24 | 235 | if not authed_hosts: | 236 | if not authed_hosts: |
26 | 236 | log('Peer %s has not authorized *any* hosts yet, skipping.') | 237 | log('Peer %s has not authorized *any* hosts yet, skipping.' % |
27 | 238 | (unit), level=INFO) | ||
28 | 237 | continue | 239 | continue |
29 | 238 | 240 | ||
30 | 239 | if unit_private_ip() in authed_hosts.split(':'): | 241 | if unit_private_ip() in authed_hosts.split(':'): |
31 | 240 | hosts.append(private_addr) | 242 | hosts.append(private_addr) |
32 | 241 | else: | 243 | else: |
35 | 242 | log('Peer %s has not authorized *this* host yet, skipping.') | 244 | log('Peer %s has not authorized *this* host yet, skipping.' % |
36 | 243 | 245 | (unit), level=INFO) | |
37 | 244 | return hosts | 246 | return hosts |
38 | 245 | 247 | ||
39 | 246 | 248 | ||
40 | 247 | 249 | ||
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 | 26 | from charmhelpers.core.hookenv import ( | 26 | from charmhelpers.core.hookenv import ( |
46 | 27 | log, | 27 | log, |
47 | 28 | DEBUG, | 28 | DEBUG, |
48 | 29 | ERROR, | ||
49 | 29 | ) | 30 | ) |
50 | 30 | 31 | ||
51 | 31 | 32 | ||
52 | 32 | def create(sysctl_dict, sysctl_file): | 33 | def create(sysctl_dict, sysctl_file): |
53 | 33 | """Creates a sysctl.conf file from a YAML associative array | 34 | """Creates a sysctl.conf file from a YAML associative array |
54 | 34 | 35 | ||
57 | 35 | :param sysctl_dict: a dict of sysctl options eg { 'kernel.max_pid': 1337 } | 36 | :param sysctl_dict: a YAML-formatted string of sysctl options eg "{ 'kernel.max_pid': 1337 }" |
58 | 36 | :type sysctl_dict: dict | 37 | :type sysctl_dict: str |
59 | 37 | :param sysctl_file: path to the sysctl file to be saved | 38 | :param sysctl_file: path to the sysctl file to be saved |
60 | 38 | :type sysctl_file: str or unicode | 39 | :type sysctl_file: str or unicode |
61 | 39 | :returns: None | 40 | :returns: None |
62 | 40 | """ | 41 | """ |
64 | 41 | sysctl_dict = yaml.load(sysctl_dict) | 42 | try: |
65 | 43 | sysctl_dict_parsed = yaml.safe_load(sysctl_dict) | ||
66 | 44 | except yaml.YAMLError: | ||
67 | 45 | log("Error parsing YAML sysctl_dict: {}".format(sysctl_dict), | ||
68 | 46 | level=ERROR) | ||
69 | 47 | return | ||
70 | 42 | 48 | ||
71 | 43 | with open(sysctl_file, "w") as fd: | 49 | with open(sysctl_file, "w") as fd: |
73 | 44 | for key, value in sysctl_dict.items(): | 50 | for key, value in sysctl_dict_parsed.items(): |
74 | 45 | fd.write("{}={}\n".format(key, value)) | 51 | fd.write("{}={}\n".format(key, value)) |
75 | 46 | 52 | ||
77 | 47 | log("Updating sysctl_file: %s values: %s" % (sysctl_file, sysctl_dict), | 53 | log("Updating sysctl_file: %s values: %s" % (sysctl_file, sysctl_dict_parsed), |
78 | 48 | level=DEBUG) | 54 | level=DEBUG) |
79 | 49 | 55 | ||
80 | 50 | check_call(["sysctl", "-p", sysctl_file]) | 56 | check_call(["sysctl", "-p", sysctl_file]) |
81 | 51 | 57 | ||
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 | 67 | is_str_true, | 67 | is_str_true, |
87 | 68 | is_ssl_cert_master, | 68 | is_ssl_cert_master, |
88 | 69 | is_db_ready, | 69 | is_db_ready, |
89 | 70 | clear_ssl_synced_units, | ||
90 | 70 | ) | 71 | ) |
91 | 71 | 72 | ||
92 | 72 | from charmhelpers.contrib.hahelpers.cluster import ( | 73 | from charmhelpers.contrib.hahelpers.cluster import ( |
93 | @@ -150,11 +151,8 @@ | |||
94 | 150 | admin_relation_changed(rid) | 151 | admin_relation_changed(rid) |
95 | 151 | 152 | ||
96 | 152 | # Ensure sync request is sent out (needed for upgrade to ssl from non-ssl) | 153 | # Ensure sync request is sent out (needed for upgrade to ssl from non-ssl) |
102 | 153 | settings = {} | 154 | send_ssl_sync_request() |
103 | 154 | append_ssl_sync_request(settings) | 155 | |
99 | 155 | if settings: | ||
100 | 156 | for rid in relation_ids('cluster'): | ||
101 | 157 | relation_set(relation_id=rid, relation_settings=settings) | ||
104 | 158 | for r_id in relation_ids('ha'): | 156 | for r_id in relation_ids('ha'): |
105 | 159 | ha_joined(relation_id=r_id) | 157 | ha_joined(relation_id=r_id) |
106 | 160 | 158 | ||
107 | @@ -283,15 +281,39 @@ | |||
108 | 283 | send_notifications(notifications) | 281 | send_notifications(notifications) |
109 | 284 | 282 | ||
110 | 285 | 283 | ||
115 | 286 | def append_ssl_sync_request(settings): | 284 | def send_ssl_sync_request(): |
116 | 287 | """Add request to be synced to relation settings. | 285 | """Set sync request on cluster relation. |
117 | 288 | 286 | ||
118 | 289 | This will be consumed by cluster-relation-changed ssl master. | 287 | Value set equals number of ssl configs currently enabled so that if they |
119 | 288 | change, we ensure that certs are synced. This setting is consumed by | ||
120 | 289 | cluster-relation-changed ssl master. We also clear the 'synced' set to | ||
121 | 290 | guarantee that a sync will occur. | ||
122 | 291 | |||
123 | 292 | Note the we do nothing if the setting is already applied. | ||
124 | 290 | """ | 293 | """ |
129 | 291 | if (is_str_true(config('use-https')) or | 294 | unit = local_unit().replace('/', '-') |
130 | 292 | is_str_true(config('https-service-endpoints'))): | 295 | count = 0 |
131 | 293 | unit = local_unit().replace('/', '-') | 296 | if is_str_true(config('use-https')): |
132 | 294 | settings['ssl-sync-required-%s' % (unit)] = '1' | 297 | count += 1 |
133 | 298 | |||
134 | 299 | if is_str_true(config('https-service-endpoints')): | ||
135 | 300 | count += 2 | ||
136 | 301 | |||
137 | 302 | if count: | ||
138 | 303 | key = 'ssl-sync-required-%s' % (unit) | ||
139 | 304 | settings = {key: count} | ||
140 | 305 | prev = 0 | ||
141 | 306 | rid = None | ||
142 | 307 | for rid in relation_ids('cluster'): | ||
143 | 308 | for unit in related_units(rid): | ||
144 | 309 | _prev = relation_get(rid=rid, unit=unit, attribute=key) or 0 | ||
145 | 310 | if _prev and _prev > prev: | ||
146 | 311 | prev = _prev | ||
147 | 312 | |||
148 | 313 | if rid and prev < count: | ||
149 | 314 | clear_ssl_synced_units() | ||
150 | 315 | log("Setting %s=%s" % (key, count), level=DEBUG) | ||
151 | 316 | relation_set(relation_id=rid, relation_settings=settings) | ||
152 | 295 | 317 | ||
153 | 296 | 318 | ||
154 | 297 | @hooks.hook('cluster-relation-joined') | 319 | @hooks.hook('cluster-relation-joined') |
155 | @@ -314,9 +336,8 @@ | |||
156 | 314 | private_addr = get_ipv6_addr(exc_list=[config('vip')])[0] | 336 | private_addr = get_ipv6_addr(exc_list=[config('vip')])[0] |
157 | 315 | settings['private-address'] = private_addr | 337 | settings['private-address'] = private_addr |
158 | 316 | 338 | ||
159 | 317 | append_ssl_sync_request(settings) | ||
160 | 318 | |||
161 | 319 | relation_set(relation_settings=settings) | 339 | relation_set(relation_settings=settings) |
162 | 340 | send_ssl_sync_request() | ||
163 | 320 | 341 | ||
164 | 321 | 342 | ||
165 | 322 | def apply_echo_filters(settings, echo_whitelist): | 343 | def apply_echo_filters(settings, echo_whitelist): |
166 | 323 | 344 | ||
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 | 21 | determine_api_port, | 21 | determine_api_port, |
172 | 22 | https, | 22 | https, |
173 | 23 | peer_units, | 23 | peer_units, |
174 | 24 | oldest_peer, | ||
175 | 25 | ) | 24 | ) |
176 | 26 | 25 | ||
177 | 27 | from charmhelpers.contrib.openstack import context, templating | 26 | from charmhelpers.contrib.openstack import context, templating |
178 | @@ -764,14 +763,27 @@ | |||
179 | 764 | def unison_sync(paths_to_sync): | 763 | def unison_sync(paths_to_sync): |
180 | 765 | """Do unison sync and retry a few times if it fails since peers may not be | 764 | """Do unison sync and retry a few times if it fails since peers may not be |
181 | 766 | ready for sync. | 765 | ready for sync. |
182 | 766 | |||
183 | 767 | Returns list of synced units or None if one or more peers was not synced. | ||
184 | 767 | """ | 768 | """ |
185 | 768 | log('Synchronizing CA (%s) to all peers.' % (', '.join(paths_to_sync)), | 769 | log('Synchronizing CA (%s) to all peers.' % (', '.join(paths_to_sync)), |
186 | 769 | level=INFO) | 770 | level=INFO) |
187 | 770 | keystone_gid = grp.getgrnam('keystone').gr_gid | 771 | keystone_gid = grp.getgrnam('keystone').gr_gid |
188 | 772 | |||
189 | 773 | # NOTE(dosaboy): This will sync to all peers who have already provided | ||
190 | 774 | # their ssh keys. If any existing peers have not provided their keys yet, | ||
191 | 775 | # they will be silently ignored. | ||
192 | 771 | unison.sync_to_peers(peer_interface='cluster', paths=paths_to_sync, | 776 | unison.sync_to_peers(peer_interface='cluster', paths=paths_to_sync, |
193 | 772 | user=SSH_USER, verbose=True, gid=keystone_gid, | 777 | user=SSH_USER, verbose=True, gid=keystone_gid, |
194 | 773 | fatal=True) | 778 | fatal=True) |
195 | 774 | 779 | ||
196 | 780 | synced_units = peer_units() | ||
197 | 781 | if len(unison.collect_authed_hosts('cluster')) != len(synced_units): | ||
198 | 782 | log("Not all peer units synced due to missing public keys", level=INFO) | ||
199 | 783 | return None | ||
200 | 784 | else: | ||
201 | 785 | return synced_units | ||
202 | 786 | |||
203 | 775 | 787 | ||
204 | 776 | def get_ssl_sync_request_units(): | 788 | def get_ssl_sync_request_units(): |
205 | 777 | """Get list of units that have requested to be synced. | 789 | """Get list of units that have requested to be synced. |
206 | @@ -791,14 +803,22 @@ | |||
207 | 791 | return units | 803 | return units |
208 | 792 | 804 | ||
209 | 793 | 805 | ||
211 | 794 | def is_ssl_cert_master(): | 806 | def is_ssl_cert_master(votes=None): |
212 | 795 | """Return True if this unit is ssl cert master.""" | 807 | """Return True if this unit is ssl cert master.""" |
213 | 796 | master = None | 808 | master = None |
214 | 797 | for rid in relation_ids('cluster'): | 809 | for rid in relation_ids('cluster'): |
215 | 798 | master = relation_get(attribute='ssl-cert-master', rid=rid, | 810 | master = relation_get(attribute='ssl-cert-master', rid=rid, |
216 | 799 | unit=local_unit()) | 811 | unit=local_unit()) |
217 | 800 | 812 | ||
219 | 801 | return master == local_unit() | 813 | if master == local_unit(): |
220 | 814 | votes = votes or get_ssl_cert_master_votes() | ||
221 | 815 | if not peer_units() or (len(votes) == 1 and master in votes): | ||
222 | 816 | return True | ||
223 | 817 | |||
224 | 818 | log("Did not get consensus from peers on who is ssl-cert-master " | ||
225 | 819 | "(%s)" % (votes), level=INFO) | ||
226 | 820 | |||
227 | 821 | return False | ||
228 | 802 | 822 | ||
229 | 803 | 823 | ||
230 | 804 | def is_ssl_enabled(): | 824 | def is_ssl_enabled(): |
231 | @@ -812,7 +832,21 @@ | |||
232 | 812 | return True | 832 | return True |
233 | 813 | 833 | ||
234 | 814 | 834 | ||
236 | 815 | def ensure_ssl_cert_master(use_oldest_peer=False): | 835 | def get_ssl_cert_master_votes(): |
237 | 836 | """Returns a list of unique votes.""" | ||
238 | 837 | votes = [] | ||
239 | 838 | # Gather election results from peers. These will need to be consistent. | ||
240 | 839 | for rid in relation_ids('cluster'): | ||
241 | 840 | for unit in related_units(rid): | ||
242 | 841 | m = relation_get(rid=rid, unit=unit, | ||
243 | 842 | attribute='ssl-cert-master') | ||
244 | 843 | if m is not None: | ||
245 | 844 | votes.append(m) | ||
246 | 845 | |||
247 | 846 | return list(set(votes)) | ||
248 | 847 | |||
249 | 848 | |||
250 | 849 | def ensure_ssl_cert_master(): | ||
251 | 816 | """Ensure that an ssl cert master has been elected. | 850 | """Ensure that an ssl cert master has been elected. |
252 | 817 | 851 | ||
253 | 818 | Normally the cluster leader will take control but we allow for this to be | 852 | Normally the cluster leader will take control but we allow for this to be |
254 | @@ -822,31 +856,19 @@ | |||
255 | 822 | if not is_ssl_enabled(): | 856 | if not is_ssl_enabled(): |
256 | 823 | return False | 857 | return False |
257 | 824 | 858 | ||
258 | 825 | elect = False | ||
259 | 826 | peers = peer_units() | ||
260 | 827 | master_override = False | 859 | master_override = False |
265 | 828 | if use_oldest_peer: | 860 | elect = is_elected_leader(CLUSTER_RES) |
262 | 829 | elect = oldest_peer(peers) | ||
263 | 830 | else: | ||
264 | 831 | elect = is_elected_leader(CLUSTER_RES) | ||
266 | 832 | 861 | ||
267 | 833 | # If no peers we allow this unit to elect itsef as master and do | 862 | # If no peers we allow this unit to elect itsef as master and do |
268 | 834 | # sync immediately. | 863 | # sync immediately. |
270 | 835 | if not peers and not is_ssl_cert_master(): | 864 | if not peer_units(): |
271 | 836 | elect = True | 865 | elect = True |
272 | 837 | master_override = True | 866 | master_override = True |
273 | 838 | 867 | ||
274 | 839 | if elect: | 868 | if elect: |
283 | 840 | masters = [] | 869 | votes = get_ssl_cert_master_votes() |
276 | 841 | for rid in relation_ids('cluster'): | ||
277 | 842 | for unit in related_units(rid): | ||
278 | 843 | m = relation_get(rid=rid, unit=unit, | ||
279 | 844 | attribute='ssl-cert-master') | ||
280 | 845 | if m is not None: | ||
281 | 846 | masters.append(m) | ||
282 | 847 | |||
284 | 848 | # We expect all peers to echo this setting | 870 | # We expect all peers to echo this setting |
286 | 849 | if not masters or 'unknown' in masters: | 871 | if not votes or 'unknown' in votes: |
287 | 850 | log("Notifying peers this unit is ssl-cert-master", level=INFO) | 872 | log("Notifying peers this unit is ssl-cert-master", level=INFO) |
288 | 851 | for rid in relation_ids('cluster'): | 873 | for rid in relation_ids('cluster'): |
289 | 852 | settings = {'ssl-cert-master': local_unit()} | 874 | settings = {'ssl-cert-master': local_unit()} |
290 | @@ -855,10 +877,11 @@ | |||
291 | 855 | # Return now and wait for cluster-relation-changed (peer_echo) for | 877 | # Return now and wait for cluster-relation-changed (peer_echo) for |
292 | 856 | # sync. | 878 | # sync. |
293 | 857 | return master_override | 879 | return master_override |
298 | 858 | elif len(set(masters)) != 1 and local_unit() not in masters: | 880 | elif not is_ssl_cert_master(votes): |
299 | 859 | log("Did not get consensus from peers on who is ssl-cert-master " | 881 | if not master_override: |
300 | 860 | "(%s) - waiting for current master to release before " | 882 | log("Conscensus not reached - current master will need to " |
301 | 861 | "self-electing" % (masters), level=INFO) | 883 | "release", level=INFO) |
302 | 884 | |||
303 | 862 | return master_override | 885 | return master_override |
304 | 863 | 886 | ||
305 | 864 | if not is_ssl_cert_master(): | 887 | if not is_ssl_cert_master(): |
306 | @@ -887,15 +910,18 @@ | |||
307 | 887 | log("Syncing all endpoint certs since https-service-endpoints=True", | 910 | log("Syncing all endpoint certs since https-service-endpoints=True", |
308 | 888 | level=DEBUG) | 911 | level=DEBUG) |
309 | 889 | paths_to_sync.append(SSL_DIR) | 912 | paths_to_sync.append(SSL_DIR) |
310 | 890 | paths_to_sync.append(APACHE_SSL_DIR) | ||
311 | 891 | paths_to_sync.append(CA_CERT_PATH) | 913 | paths_to_sync.append(CA_CERT_PATH) |
313 | 892 | elif is_str_true(config('use-https')): | 914 | |
314 | 915 | if is_str_true(config('use-https')): | ||
315 | 893 | log("Syncing keystone-endpoint certs since use-https=True", | 916 | log("Syncing keystone-endpoint certs since use-https=True", |
316 | 894 | level=DEBUG) | 917 | level=DEBUG) |
317 | 895 | paths_to_sync.append(SSL_DIR) | 918 | paths_to_sync.append(SSL_DIR) |
318 | 896 | paths_to_sync.append(APACHE_SSL_DIR) | 919 | paths_to_sync.append(APACHE_SSL_DIR) |
319 | 897 | paths_to_sync.append(CA_CERT_PATH) | 920 | paths_to_sync.append(CA_CERT_PATH) |
320 | 898 | 921 | ||
321 | 922 | # Ensure unique | ||
322 | 923 | paths_to_sync = list(set(paths_to_sync)) | ||
323 | 924 | |||
324 | 899 | if not paths_to_sync: | 925 | if not paths_to_sync: |
325 | 900 | log("Nothing to sync - skipping", level=DEBUG) | 926 | log("Nothing to sync - skipping", level=DEBUG) |
326 | 901 | return {} | 927 | return {} |
327 | @@ -908,8 +934,7 @@ | |||
328 | 908 | create_peer_service_actions('restart', ['apache2']) | 934 | create_peer_service_actions('restart', ['apache2']) |
329 | 909 | create_peer_actions(['update-ca-certificates']) | 935 | create_peer_actions(['update-ca-certificates']) |
330 | 910 | 936 | ||
333 | 911 | # Format here needs to match that used when peers request sync | 937 | cluster_rel_settings = {} |
332 | 912 | synced_units = [unit.replace('/', '-') for unit in peer_units()] | ||
334 | 913 | 938 | ||
335 | 914 | retries = 3 | 939 | retries = 3 |
336 | 915 | while True: | 940 | while True: |
337 | @@ -918,7 +943,12 @@ | |||
338 | 918 | update_hash_from_path(hash1, path) | 943 | update_hash_from_path(hash1, path) |
339 | 919 | 944 | ||
340 | 920 | try: | 945 | try: |
342 | 921 | unison_sync(paths_to_sync) | 946 | synced_units = unison_sync(paths_to_sync) |
343 | 947 | if synced_units: | ||
344 | 948 | # Format here needs to match that used when peers request sync | ||
345 | 949 | synced_units = [u.replace('/', '-') for u in synced_units] | ||
346 | 950 | cluster_rel_settings['ssl-synced-units'] = \ | ||
347 | 951 | json.dumps(synced_units) | ||
348 | 922 | except: | 952 | except: |
349 | 923 | if fatal: | 953 | if fatal: |
350 | 924 | raise | 954 | raise |
351 | @@ -947,10 +977,22 @@ | |||
352 | 947 | hash = hash1.hexdigest() | 977 | hash = hash1.hexdigest() |
353 | 948 | log("Sending restart-services-trigger=%s to all peers" % (hash), | 978 | log("Sending restart-services-trigger=%s to all peers" % (hash), |
354 | 949 | level=DEBUG) | 979 | level=DEBUG) |
355 | 980 | cluster_rel_settings['restart-services-trigger'] = hash | ||
356 | 950 | 981 | ||
357 | 951 | log("Sync complete", level=DEBUG) | 982 | log("Sync complete", level=DEBUG) |
360 | 952 | return {'restart-services-trigger': hash, | 983 | return cluster_rel_settings |
361 | 953 | 'ssl-synced-units': json.dumps(synced_units)} | 984 | |
362 | 985 | |||
363 | 986 | def clear_ssl_synced_units(): | ||
364 | 987 | """Clear the 'synced' units record on the cluster relation. | ||
365 | 988 | |||
366 | 989 | If new unit sync reauests are set this will ensure that a sync occurs when | ||
367 | 990 | the sync master receives the requests. | ||
368 | 991 | """ | ||
369 | 992 | log("Clearing ssl sync units", level=DEBUG) | ||
370 | 993 | for rid in relation_ids('cluster'): | ||
371 | 994 | relation_set(relation_id=rid, | ||
372 | 995 | relation_settings={'ssl-synced-units': None}) | ||
373 | 954 | 996 | ||
374 | 955 | 997 | ||
375 | 956 | def update_hash_from_path(hash, path, recurse_depth=10): | 998 | def update_hash_from_path(hash, path, recurse_depth=10): |
376 | @@ -1058,11 +1100,11 @@ | |||
377 | 1058 | '%s' % SSL_DIR]) | 1100 | '%s' % SSL_DIR]) |
378 | 1059 | subprocess.check_output(['chmod', '-R', 'g+rwx', '%s' % SSL_DIR]) | 1101 | subprocess.check_output(['chmod', '-R', 'g+rwx', '%s' % SSL_DIR]) |
379 | 1060 | 1102 | ||
385 | 1061 | # Ensure a master has been elected and prefer this unit. Note that we | 1103 | # Ensure a master is elected. This should cover the following cases: |
386 | 1062 | # prefer oldest peer as predicate since this action i normally only | 1104 | # * single unit == 'oldest' unit is elected as master |
387 | 1063 | # performed once at deploy time when the oldest peer should be the | 1105 | # * multi unit + not clustered == 'oldest' unit is elcted as master |
388 | 1064 | # first to be ready. | 1106 | # * multi unit + clustered == cluster leader is elected as master |
389 | 1065 | ensure_ssl_cert_master(use_oldest_peer=True) | 1107 | ensure_ssl_cert_master() |
390 | 1066 | 1108 | ||
391 | 1067 | ssl.CA_SINGLETON.append(ca) | 1109 | ssl.CA_SINGLETON.append(ca) |
392 | 1068 | 1110 | ||
393 | 1069 | 1111 | ||
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 | 28 | 'grant_role', | 28 | 'grant_role', |
399 | 29 | 'configure_installation_source', | 29 | 'configure_installation_source', |
400 | 30 | 'is_elected_leader', | 30 | 'is_elected_leader', |
401 | 31 | 'is_ssl_cert_master', | ||
402 | 31 | 'https', | 32 | 'https', |
403 | 32 | 'peer_store_and_set', | 33 | 'peer_store_and_set', |
404 | 33 | 'service_stop', | 34 | 'service_stop', |
405 | @@ -380,45 +381,141 @@ | |||
406 | 380 | self.assertTrue(utils.is_db_ready()) | 381 | self.assertTrue(utils.is_db_ready()) |
407 | 381 | 382 | ||
408 | 382 | @patch.object(utils, 'peer_units') | 383 | @patch.object(utils, 'peer_units') |
451 | 383 | @patch.object(utils, 'is_elected_leader') | 384 | @patch.object(utils, 'is_ssl_enabled') |
452 | 384 | @patch.object(utils, 'oldest_peer') | 385 | def test_ensure_ssl_cert_master_no_ssl(self, mock_is_ssl_enabled, |
453 | 385 | @patch.object(utils, 'is_ssl_enabled') | 386 | mock_peer_units): |
454 | 386 | def test_ensure_ssl_cert_master(self, mock_is_str_true, mock_oldest_peer, | 387 | mock_is_ssl_enabled.return_value = False |
455 | 387 | mock_is_elected_leader, mock_peer_units): | 388 | self.assertFalse(utils.ensure_ssl_cert_master()) |
456 | 388 | self.relation_ids.return_value = ['cluster:0'] | 389 | self.assertFalse(self.relation_set.called) |
457 | 389 | self.local_unit.return_value = 'unit/0' | 390 | |
458 | 390 | 391 | @patch.object(utils, 'peer_units') | |
459 | 391 | mock_is_str_true.return_value = False | 392 | @patch.object(utils, 'is_ssl_enabled') |
460 | 392 | self.assertFalse(utils.ensure_ssl_cert_master()) | 393 | def test_ensure_ssl_cert_master_ssl_no_peers(self, mock_is_ssl_enabled, |
461 | 393 | self.assertFalse(self.relation_set.called) | 394 | mock_peer_units): |
462 | 394 | 395 | def mock_rel_get(unit=None, **kwargs): | |
463 | 395 | mock_is_elected_leader.return_value = False | 396 | return None |
464 | 396 | self.assertFalse(utils.ensure_ssl_cert_master()) | 397 | |
465 | 397 | self.assertFalse(self.relation_set.called) | 398 | self.relation_get.side_effect = mock_rel_get |
466 | 398 | 399 | mock_is_ssl_enabled.return_value = True | |
467 | 399 | mock_is_str_true.return_value = True | 400 | self.relation_ids.return_value = ['cluster:0'] |
468 | 400 | mock_is_elected_leader.return_value = False | 401 | self.local_unit.return_value = 'unit/0' |
469 | 401 | mock_peer_units.return_value = ['unit/0'] | 402 | self.related_units.return_value = [] |
470 | 402 | self.assertFalse(utils.ensure_ssl_cert_master()) | 403 | mock_peer_units.return_value = [] |
471 | 403 | self.assertFalse(self.relation_set.called) | 404 | # This should get ignored since we are overriding |
472 | 404 | 405 | self.is_ssl_cert_master.return_value = False | |
473 | 405 | mock_peer_units.return_value = [] | 406 | self.is_elected_leader.return_value = False |
474 | 406 | self.assertTrue(utils.ensure_ssl_cert_master()) | 407 | self.assertTrue(utils.ensure_ssl_cert_master()) |
475 | 407 | settings = {'ssl-cert-master': 'unit/0'} | 408 | settings = {'ssl-cert-master': 'unit/0'} |
476 | 408 | self.relation_set.assert_called_with(relation_id='cluster:0', | 409 | self.relation_set.assert_called_with(relation_id='cluster:0', |
477 | 409 | relation_settings=settings) | 410 | relation_settings=settings) |
478 | 410 | self.relation_set.reset_mock() | 411 | |
479 | 411 | 412 | @patch.object(utils, 'peer_units') | |
480 | 412 | self.assertTrue(utils.ensure_ssl_cert_master(use_oldest_peer=True)) | 413 | @patch.object(utils, 'is_ssl_enabled') |
481 | 413 | settings = {'ssl-cert-master': 'unit/0'} | 414 | def test_ensure_ssl_cert_master_ssl_master_no_peers(self, |
482 | 414 | self.relation_set.assert_called_with(relation_id='cluster:0', | 415 | mock_is_ssl_enabled, |
483 | 415 | relation_settings=settings) | 416 | mock_peer_units): |
484 | 416 | self.relation_set.reset_mock() | 417 | def mock_rel_get(unit=None, **kwargs): |
485 | 417 | 418 | if unit == 'unit/0': | |
486 | 418 | mock_peer_units.return_value = ['unit/0'] | 419 | return 'unit/0' |
487 | 419 | self.assertFalse(utils.ensure_ssl_cert_master()) | 420 | |
488 | 420 | self.assertFalse(utils.ensure_ssl_cert_master(use_oldest_peer=True)) | 421 | return None |
489 | 421 | settings = {'ssl-cert-master': 'unit/0'} | 422 | |
490 | 422 | self.relation_set.assert_called_with(relation_id='cluster:0', | 423 | self.relation_get.side_effect = mock_rel_get |
491 | 423 | relation_settings=settings) | 424 | mock_is_ssl_enabled.return_value = True |
492 | 424 | self.relation_set.reset_mock() | 425 | self.relation_ids.return_value = ['cluster:0'] |
493 | 426 | self.local_unit.return_value = 'unit/0' | ||
494 | 427 | self.related_units.return_value = [] | ||
495 | 428 | mock_peer_units.return_value = [] | ||
496 | 429 | # This should get ignored since we are overriding | ||
497 | 430 | self.is_ssl_cert_master.return_value = False | ||
498 | 431 | self.is_elected_leader.return_value = False | ||
499 | 432 | self.assertTrue(utils.ensure_ssl_cert_master()) | ||
500 | 433 | settings = {'ssl-cert-master': 'unit/0'} | ||
501 | 434 | self.relation_set.assert_called_with(relation_id='cluster:0', | ||
502 | 435 | relation_settings=settings) | ||
503 | 436 | |||
504 | 437 | @patch.object(utils, 'peer_units') | ||
505 | 438 | @patch.object(utils, 'is_ssl_enabled') | ||
506 | 439 | def test_ensure_ssl_cert_master_ssl_not_leader(self, mock_is_ssl_enabled, | ||
507 | 440 | mock_peer_units): | ||
508 | 441 | mock_is_ssl_enabled.return_value = True | ||
509 | 442 | self.relation_ids.return_value = ['cluster:0'] | ||
510 | 443 | self.local_unit.return_value = 'unit/0' | ||
511 | 444 | mock_peer_units.return_value = ['unit/1'] | ||
512 | 445 | self.is_ssl_cert_master.return_value = False | ||
513 | 446 | self.is_elected_leader.return_value = False | ||
514 | 447 | self.assertFalse(utils.ensure_ssl_cert_master()) | ||
515 | 448 | self.assertFalse(self.relation_set.called) | ||
516 | 449 | |||
517 | 450 | @patch.object(utils, 'peer_units') | ||
518 | 451 | @patch.object(utils, 'is_ssl_enabled') | ||
519 | 452 | def test_ensure_ssl_cert_master_is_leader_new_peer(self, | ||
520 | 453 | mock_is_ssl_enabled, | ||
521 | 454 | mock_peer_units): | ||
522 | 455 | def mock_rel_get(unit=None, **kwargs): | ||
523 | 456 | if unit == 'unit/0': | ||
524 | 457 | return 'unit/0' | ||
525 | 458 | |||
526 | 459 | return 'unknown' | ||
527 | 460 | |||
528 | 461 | self.relation_get.side_effect = mock_rel_get | ||
529 | 462 | mock_is_ssl_enabled.return_value = True | ||
530 | 463 | self.relation_ids.return_value = ['cluster:0'] | ||
531 | 464 | self.local_unit.return_value = 'unit/0' | ||
532 | 465 | mock_peer_units.return_value = ['unit/1'] | ||
533 | 466 | self.related_units.return_value = ['unit/1'] | ||
534 | 467 | self.is_ssl_cert_master.return_value = False | ||
535 | 468 | self.is_elected_leader.return_value = True | ||
536 | 469 | self.assertFalse(utils.ensure_ssl_cert_master()) | ||
537 | 470 | settings = {'ssl-cert-master': 'unit/0'} | ||
538 | 471 | self.relation_set.assert_called_with(relation_id='cluster:0', | ||
539 | 472 | relation_settings=settings) | ||
540 | 473 | |||
541 | 474 | @patch.object(utils, 'peer_units') | ||
542 | 475 | @patch.object(utils, 'is_ssl_enabled') | ||
543 | 476 | def test_ensure_ssl_cert_master_is_leader_no_new_peer(self, | ||
544 | 477 | mock_is_ssl_enabled, | ||
545 | 478 | mock_peer_units): | ||
546 | 479 | def mock_rel_get(unit=None, **kwargs): | ||
547 | 480 | if unit == 'unit/0': | ||
548 | 481 | return 'unit/0' | ||
549 | 482 | |||
550 | 483 | return 'unit/0' | ||
551 | 484 | |||
552 | 485 | self.relation_get.side_effect = mock_rel_get | ||
553 | 486 | mock_is_ssl_enabled.return_value = True | ||
554 | 487 | self.relation_ids.return_value = ['cluster:0'] | ||
555 | 488 | self.local_unit.return_value = 'unit/0' | ||
556 | 489 | mock_peer_units.return_value = ['unit/1'] | ||
557 | 490 | self.related_units.return_value = ['unit/1'] | ||
558 | 491 | self.is_ssl_cert_master.return_value = False | ||
559 | 492 | self.is_elected_leader.return_value = True | ||
560 | 493 | self.assertFalse(utils.ensure_ssl_cert_master()) | ||
561 | 494 | self.assertFalse(self.relation_set.called) | ||
562 | 495 | |||
563 | 496 | @patch.object(utils, 'peer_units') | ||
564 | 497 | @patch.object(utils, 'is_ssl_enabled') | ||
565 | 498 | def test_ensure_ssl_cert_master_is_leader_bad_votes(self, | ||
566 | 499 | mock_is_ssl_enabled, | ||
567 | 500 | mock_peer_units): | ||
568 | 501 | counter = {0: 0} | ||
569 | 502 | |||
570 | 503 | def mock_rel_get(unit=None, **kwargs): | ||
571 | 504 | """Returns a mix of votes.""" | ||
572 | 505 | if unit == 'unit/0': | ||
573 | 506 | return 'unit/0' | ||
574 | 507 | |||
575 | 508 | ret = 'unit/%d' % (counter[0]) | ||
576 | 509 | counter[0] += 1 | ||
577 | 510 | return ret | ||
578 | 511 | |||
579 | 512 | self.relation_get.side_effect = mock_rel_get | ||
580 | 513 | mock_is_ssl_enabled.return_value = True | ||
581 | 514 | self.relation_ids.return_value = ['cluster:0'] | ||
582 | 515 | self.local_unit.return_value = 'unit/0' | ||
583 | 516 | mock_peer_units.return_value = ['unit/1'] | ||
584 | 517 | self.related_units.return_value = ['unit/1'] | ||
585 | 518 | self.is_ssl_cert_master.return_value = False | ||
586 | 519 | self.is_elected_leader.return_value = True | ||
587 | 520 | self.assertFalse(utils.ensure_ssl_cert_master()) | ||
588 | 521 | 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/