Merge lp:~niedbalski/charms/trusty/rabbitmq-server/fix-1442443 into lp:charms/trusty/rabbitmq-server
- Trusty Tahr (14.04)
- fix-1442443
- Merge into trunk
Status: | Superseded | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~niedbalski/charms/trusty/rabbitmq-server/fix-1442443 | ||||
Merge into: | lp:charms/trusty/rabbitmq-server | ||||
Diff against target: |
746 lines (+373/-168) 11 files modified
config.yaml (+7/-1) hooks/rabbit_utils.py (+37/-39) hooks/rabbitmq_context.py (+125/-0) hooks/rabbitmq_server_relations.py (+7/-113) hooks/ssl_utils.py (+55/-0) templates/rabbitmq.config (+25/-11) tests/00_setup.sh (+3/-0) tests/50_test_cluster_partition.py (+31/-0) unit_tests/test_rabbit_utils.py (+1/-1) unit_tests/test_rabbitmq_context.py (+79/-0) unit_tests/test_rabbitmq_server_relations.py (+3/-3) |
||||
To merge this branch: | bzr merge lp:~niedbalski/charms/trusty/rabbitmq-server/fix-1442443 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Billy Olsen | Needs Fixing | ||
OpenStack Charmers | Pending | ||
Review via email: mp+255770@code.launchpad.net |
This proposal has been superseded by a proposal from 2015-04-10.
Commit message
Description of the change
- Added the cluster_
- Refactored the ssl handling code.
- Added a generic config loader
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #3202 rabbitmq-server for niedbalski mp255770
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #2990 rabbitmq-server for niedbalski mp255770
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #3019 rabbitmq-server for niedbalski mp255770
AMULET FAIL: amulet-test failed
AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.
Full amulet test output: http://
Build: http://
- 89. By Liam Young
-
[gnuoy,trivial] Pre-release charmhelper sync
- 90. By James Page
-
[wolsen,
r=james- page] Fixup SSL tests to not fail when certs expire! - 91. By Jorge Niedbalski
-
Rebase commit
- 92. By Jorge Niedbalski
-
Rebase
- 93. By Jorge Niedbalski
-
addressing @dosaboy comments
- 94. By Jorge Niedbalski
-
addressing @dosaboy comments
- 95. By Jorge Niedbalski
-
addressing @dosaboy comments
- 96. By Jorge Niedbalski
-
addressing comments
- 97. By Jorge Niedbalski
-
Addressed @beisner comments
- 98. By Jorge Niedbalski
-
Addressed @beisner comments
Unmerged revisions
- 98. By Jorge Niedbalski
-
Addressed @beisner comments
- 97. By Jorge Niedbalski
-
Addressed @beisner comments
- 96. By Jorge Niedbalski
-
addressing comments
- 95. By Jorge Niedbalski
-
addressing @dosaboy comments
- 94. By Jorge Niedbalski
-
addressing @dosaboy comments
- 93. By Jorge Niedbalski
-
addressing @dosaboy comments
- 92. By Jorge Niedbalski
-
Rebase
- 91. By Jorge Niedbalski
-
Rebase commit
Preview Diff
1 | === modified file 'config.yaml' |
2 | --- config.yaml 2015-03-03 06:05:14 +0000 |
3 | +++ config.yaml 2015-04-10 02:40:31 +0000 |
4 | @@ -8,7 +8,7 @@ |
5 | type: string |
6 | default: "off" |
7 | description: | |
8 | - Enable SSL connections on rabbitmq, valid values are 'off', 'on', 'only'. If ssl_key, |
9 | + Enable SSL connections on rabbitmq, valid values are 'off', 'on', 'only'. If ssl_key, |
10 | ssl_cert, ssl_ca are provided then then those values will be used. Otherwise |
11 | the service will act as its own certificate authority and pass its ca cert to clients. |
12 | For HA or clustered rabbits ssl key/cert must be provided. |
13 | @@ -92,6 +92,12 @@ |
14 | description: | |
15 | When set to true the 'ha-mode: all' policy is applied to all the exchages |
16 | that match the expression '^(?!amq\.).*' |
17 | + cluster-partition-handling: |
18 | + type: string |
19 | + default: ignore |
20 | + description: | |
21 | + How to respond to cluster partitions. |
22 | + See http://www.rabbitmq.com/partitions.html for further details. |
23 | rbd-size: |
24 | type: string |
25 | default: 5G |
26 | |
27 | === modified file 'hooks/rabbit_utils.py' |
28 | --- hooks/rabbit_utils.py 2015-03-24 20:17:01 +0000 |
29 | +++ hooks/rabbit_utils.py 2015-04-10 02:40:31 +0000 |
30 | @@ -1,6 +1,4 @@ |
31 | import os |
32 | -import pwd |
33 | -import grp |
34 | import re |
35 | import socket |
36 | import sys |
37 | @@ -8,6 +6,13 @@ |
38 | import glob |
39 | import tempfile |
40 | |
41 | +from rabbitmq_context import ( |
42 | + RabbitMQSSLContext, |
43 | + RabbitMQClusterContext |
44 | +) |
45 | + |
46 | +from charmhelpers.core.templating import render |
47 | + |
48 | from charmhelpers.contrib.openstack.utils import ( |
49 | get_hostname, |
50 | ) |
51 | @@ -30,8 +35,6 @@ |
52 | cmp_pkgrevno |
53 | ) |
54 | |
55 | -from charmhelpers.core.templating import render |
56 | - |
57 | from charmhelpers.contrib.peerstorage import ( |
58 | peer_store, |
59 | peer_retrieve |
60 | @@ -57,7 +60,10 @@ |
61 | # the charm doesn't concern itself with template specifics etc. |
62 | CONFIG_FILES = OrderedDict([ |
63 | (RABBITMQ_CONF, { |
64 | - 'hook_contexts': None, |
65 | + 'hook_contexts': [ |
66 | + RabbitMQSSLContext(), |
67 | + RabbitMQClusterContext(), |
68 | + ], |
69 | 'services': ['rabbitmq-server'] |
70 | }), |
71 | (ENV_CONF, { |
72 | @@ -71,6 +77,32 @@ |
73 | ]) |
74 | |
75 | |
76 | +class ConfigRenderer(): |
77 | + |
78 | + def __init__(self, config): |
79 | + self.config_data = {} |
80 | + |
81 | + for config_path, data in config.items(): |
82 | + if 'hook_contexts' in data and data['hook_contexts']: |
83 | + ctxt = {} |
84 | + for svc_context in data['hook_contexts']: |
85 | + ctxt.update(svc_context()) |
86 | + self.config_data[config_path] = ctxt |
87 | + |
88 | + def write(self, config_path): |
89 | + data = self.config_data.get(config_path, None) |
90 | + if data: |
91 | + log("writing config file: %s , data: %s" % (config_path, |
92 | + str(data)), level='DEBUG') |
93 | + |
94 | + render(os.path.basename(config_path), config_path, |
95 | + data, perms=0o644) |
96 | + |
97 | + def write_all(self): |
98 | + for service in self.config_data.keys(): |
99 | + self.write(service) |
100 | + |
101 | + |
102 | class RabbitmqError(Exception): |
103 | pass |
104 | |
105 | @@ -390,40 +422,6 @@ |
106 | def disable_plugin(plugin): |
107 | _manage_plugin(plugin, 'disable') |
108 | |
109 | -ssl_key_file = "/etc/rabbitmq/rabbit-server-privkey.pem" |
110 | -ssl_cert_file = "/etc/rabbitmq/rabbit-server-cert.pem" |
111 | -ssl_ca_file = "/etc/rabbitmq/rabbit-server-ca.pem" |
112 | - |
113 | - |
114 | -def enable_ssl(ssl_key, ssl_cert, ssl_port, |
115 | - ssl_ca=None, ssl_only=False, ssl_client=None): |
116 | - uid = pwd.getpwnam("root").pw_uid |
117 | - gid = grp.getgrnam("rabbitmq").gr_gid |
118 | - |
119 | - for contents, path in ( |
120 | - (ssl_key, ssl_key_file), |
121 | - (ssl_cert, ssl_cert_file), |
122 | - (ssl_ca, ssl_ca_file)): |
123 | - if not contents: |
124 | - continue |
125 | - with open(path, 'w') as fh: |
126 | - fh.write(contents) |
127 | - os.chmod(path, 0o640) |
128 | - os.chown(path, uid, gid) |
129 | - |
130 | - data = { |
131 | - "ssl_port": ssl_port, |
132 | - "ssl_cert_file": ssl_cert_file, |
133 | - "ssl_key_file": ssl_key_file, |
134 | - "ssl_client": ssl_client, |
135 | - "ssl_ca_file": "", |
136 | - "ssl_only": ssl_only} |
137 | - |
138 | - if ssl_ca: |
139 | - data["ssl_ca_file"] = ssl_ca_file |
140 | - |
141 | - render(os.path.basename(RABBITMQ_CONF), RABBITMQ_CONF, data, perms=0o644) |
142 | - |
143 | |
144 | def execute(cmd, die=False, echo=False): |
145 | """ Executes a command |
146 | |
147 | === added file 'hooks/rabbitmq_context.py' |
148 | --- hooks/rabbitmq_context.py 1970-01-01 00:00:00 +0000 |
149 | +++ hooks/rabbitmq_context.py 2015-04-10 02:40:31 +0000 |
150 | @@ -0,0 +1,125 @@ |
151 | +from charmhelpers.contrib.ssl.service import ServiceCA |
152 | + |
153 | +from charmhelpers.core.hookenv import ( |
154 | + open_port, |
155 | + close_port, |
156 | + config, |
157 | + log, |
158 | + ERROR, |
159 | +) |
160 | + |
161 | +import sys |
162 | +import pwd |
163 | +import grp |
164 | +import os |
165 | +import base64 |
166 | + |
167 | +import ssl_utils |
168 | + |
169 | +ssl_key_file = "/etc/rabbitmq/rabbit-server-privkey.pem" |
170 | +ssl_cert_file = "/etc/rabbitmq/rabbit-server-cert.pem" |
171 | +ssl_ca_file = "/etc/rabbitmq/rabbit-server-ca.pem" |
172 | + |
173 | + |
174 | +def convert_from_base64(v): |
175 | + # Rabbit originally supported pem encoded key/cert in config, play |
176 | + # nice on upgrades as we now expect base64 encoded key/cert/ca. |
177 | + if not v: |
178 | + return v |
179 | + if v.startswith('-----BEGIN'): |
180 | + return v |
181 | + try: |
182 | + return base64.b64decode(v) |
183 | + except TypeError: |
184 | + return v |
185 | + |
186 | + |
187 | +class RabbitMQSSLContext(object): |
188 | + |
189 | + def enable_ssl(self, ssl_key, ssl_cert, ssl_port, |
190 | + ssl_ca=None, ssl_only=False, ssl_client=None): |
191 | + |
192 | + uid = pwd.getpwnam("root").pw_uid |
193 | + gid = grp.getgrnam("rabbitmq").gr_gid |
194 | + |
195 | + for contents, path in ( |
196 | + (ssl_key, ssl_key_file), |
197 | + (ssl_cert, ssl_cert_file), |
198 | + (ssl_ca, ssl_ca_file)): |
199 | + |
200 | + if not contents: |
201 | + continue |
202 | + |
203 | + with open(path, 'w') as fh: |
204 | + fh.write(contents) |
205 | + |
206 | + os.chmod(path, 0o640) |
207 | + os.chown(path, uid, gid) |
208 | + |
209 | + data = { |
210 | + "ssl_port": ssl_port, |
211 | + "ssl_cert_file": ssl_cert_file, |
212 | + "ssl_key_file": ssl_key_file, |
213 | + "ssl_client": ssl_client, |
214 | + "ssl_ca_file": "", |
215 | + "ssl_only": ssl_only |
216 | + } |
217 | + |
218 | + if ssl_ca: |
219 | + data["ssl_ca_file"] = ssl_ca_file |
220 | + |
221 | + return data |
222 | + |
223 | + def __call__(self): |
224 | + """ |
225 | + The legacy config support adds some additional complications. |
226 | + |
227 | + ssl_enabled = True, ssl = off -> ssl enabled |
228 | + ssl_enabled = False, ssl = on -> ssl enabled |
229 | + """ |
230 | + ssl_mode, external_ca = ssl_utils.get_ssl_mode() |
231 | + |
232 | + ctxt = { |
233 | + 'ssl_mode': ssl_mode, |
234 | + } |
235 | + |
236 | + if ssl_mode == 'off': |
237 | + close_port(config('ssl_port')) |
238 | + ssl_utils.reconfigure_client_ssl() |
239 | + return ctxt |
240 | + |
241 | + ssl_key = convert_from_base64(config('ssl_key')) |
242 | + ssl_cert = convert_from_base64(config('ssl_cert')) |
243 | + ssl_ca = convert_from_base64(config('ssl_ca')) |
244 | + ssl_port = config('ssl_port') |
245 | + |
246 | + # If external managed certs then we need all the fields. |
247 | + if ( |
248 | + ssl_mode in ('on', 'only') and |
249 | + any((ssl_key, ssl_cert)) and |
250 | + not all((ssl_key, ssl_cert)) |
251 | + ): |
252 | + log('If ssl_key or ssl_cert are specified both are required.', |
253 | + level=ERROR) |
254 | + sys.exit(1) |
255 | + |
256 | + if not external_ca: |
257 | + ssl_cert, ssl_key, ssl_ca = ServiceCA.get_service_cert() |
258 | + |
259 | + ctxt.update(self.enable_ssl( |
260 | + ssl_key, ssl_cert, ssl_port, ssl_ca, |
261 | + ssl_only=(ssl_mode == "only"), ssl_client=False |
262 | + )) |
263 | + |
264 | + ssl_utils.reconfigure_client_ssl(True) |
265 | + open_port(ssl_port) |
266 | + |
267 | + return ctxt |
268 | + |
269 | + |
270 | +class RabbitMQClusterContext(object): |
271 | + |
272 | + def __call__(self): |
273 | + return { |
274 | + 'cluster_partition_handling': config('cluster-partition-handling'), |
275 | + } |
276 | |
277 | === modified file 'hooks/rabbitmq_server_relations.py' |
278 | --- hooks/rabbitmq_server_relations.py 2015-03-06 06:39:19 +0000 |
279 | +++ hooks/rabbitmq_server_relations.py 2015-04-10 02:40:31 +0000 |
280 | @@ -1,5 +1,5 @@ |
281 | #!/usr/bin/python |
282 | -import base64 |
283 | + |
284 | import os |
285 | import shutil |
286 | import sys |
287 | @@ -8,6 +8,8 @@ |
288 | import socket |
289 | |
290 | import rabbit_utils as rabbit |
291 | +import ssl_utils |
292 | + |
293 | from lib.utils import ( |
294 | chown, chmod, |
295 | is_newer, |
296 | @@ -46,7 +48,6 @@ |
297 | related_units, |
298 | service_name, |
299 | local_unit, |
300 | - relations_of_type, |
301 | config, |
302 | unit_get, |
303 | is_relation_made, |
304 | @@ -61,7 +62,6 @@ |
305 | service_restart, |
306 | ) |
307 | from charmhelpers.contrib.charmsupport import nrpe |
308 | -from charmhelpers.contrib.ssl.service import ServiceCA |
309 | |
310 | from charmhelpers.contrib.peerstorage import ( |
311 | peer_echo, |
312 | @@ -176,7 +176,7 @@ |
313 | get_address_in_network(config('access-network'), |
314 | unit_get('private-address')) |
315 | |
316 | - configure_client_ssl(relation_settings) |
317 | + ssl_utils.configure_client_ssl(relation_settings) |
318 | |
319 | if is_clustered(): |
320 | relation_settings['clustered'] = 'true' |
321 | @@ -302,19 +302,6 @@ |
322 | service_restart('rabbitmq-server') |
323 | |
324 | |
325 | -@hooks.hook('cluster-relation-departed') |
326 | -def cluster_departed(): |
327 | - if is_relation_made('ha') and \ |
328 | - config('ha-vip-only') is False: |
329 | - log('hacluster relation is present, skipping native ' |
330 | - 'rabbitmq cluster config.') |
331 | - return |
332 | - if not is_newer(): |
333 | - log('cluster_joined: Relation lesser.') |
334 | - return |
335 | - rabbit.break_cluster() |
336 | - |
337 | - |
338 | @hooks.hook('ha-relation-joined') |
339 | def ha_joined(): |
340 | corosync_bindiface = config('ha-bindiface') |
341 | @@ -526,103 +513,10 @@ |
342 | MAN_PLUGIN = 'rabbitmq_management' |
343 | |
344 | |
345 | -def configure_client_ssl(relation_data): |
346 | - """Configure client with ssl |
347 | - """ |
348 | - ssl_mode, external_ca = _get_ssl_mode() |
349 | - if ssl_mode == 'off': |
350 | - return |
351 | - relation_data['ssl_port'] = config('ssl_port') |
352 | - if external_ca: |
353 | - if config('ssl_ca'): |
354 | - relation_data['ssl_ca'] = base64.b64encode( |
355 | - config('ssl_ca')) |
356 | - return |
357 | - ca = ServiceCA.get_ca() |
358 | - relation_data['ssl_ca'] = base64.b64encode(ca.get_ca_bundle()) |
359 | - |
360 | - |
361 | -def _get_ssl_mode(): |
362 | - ssl_mode = config('ssl') |
363 | - external_ca = False |
364 | - # Legacy config boolean option |
365 | - ssl_on = config('ssl_enabled') |
366 | - if ssl_mode == 'off' and ssl_on is False: |
367 | - ssl_mode = 'off' |
368 | - elif ssl_mode == 'off' and ssl_on: |
369 | - ssl_mode = 'on' |
370 | - ssl_key = config('ssl_key') |
371 | - ssl_cert = config('ssl_cert') |
372 | - if all((ssl_key, ssl_cert)): |
373 | - external_ca = True |
374 | - return ssl_mode, external_ca |
375 | - |
376 | - |
377 | -def _convert_from_base64(v): |
378 | - # Rabbit originally supported pem encoded key/cert in config, play |
379 | - # nice on upgrades as we now expect base64 encoded key/cert/ca. |
380 | - if not v: |
381 | - return v |
382 | - if v.startswith('-----BEGIN'): |
383 | - return v |
384 | - try: |
385 | - return base64.b64decode(v) |
386 | - except TypeError: |
387 | - return v |
388 | - |
389 | - |
390 | -def reconfigure_client_ssl(ssl_enabled=False): |
391 | - ssl_config_keys = set(('ssl_key', 'ssl_cert', 'ssl_ca')) |
392 | - for rid in relation_ids('amqp'): |
393 | - rdata = relation_get(rid=rid, unit=os.environ['JUJU_UNIT_NAME']) |
394 | - if not ssl_enabled and ssl_config_keys.intersection(rdata): |
395 | - # No clean way to remove entirely, but blank them. |
396 | - relation_set(relation_id=rid, ssl_key='', ssl_cert='', ssl_ca='') |
397 | - elif ssl_enabled and not ssl_config_keys.intersection(rdata): |
398 | - configure_client_ssl(rdata) |
399 | - relation_set(relation_id=rid, **rdata) |
400 | - |
401 | - |
402 | -def configure_rabbit_ssl(): |
403 | - """ |
404 | - The legacy config support adds some additional complications. |
405 | - |
406 | - ssl_enabled = True, ssl = off -> ssl enabled |
407 | - ssl_enabled = False, ssl = on -> ssl enabled |
408 | - """ |
409 | - ssl_mode, external_ca = _get_ssl_mode() |
410 | - |
411 | - if ssl_mode == 'off': |
412 | - if os.path.exists(rabbit.RABBITMQ_CONF): |
413 | - os.remove(rabbit.RABBITMQ_CONF) |
414 | - close_port(config('ssl_port')) |
415 | - reconfigure_client_ssl() |
416 | - return |
417 | - ssl_key = _convert_from_base64(config('ssl_key')) |
418 | - ssl_cert = _convert_from_base64(config('ssl_cert')) |
419 | - ssl_ca = _convert_from_base64(config('ssl_ca')) |
420 | - ssl_port = config('ssl_port') |
421 | - |
422 | - # If external managed certs then we need all the fields. |
423 | - if (ssl_mode in ('on', 'only') and any((ssl_key, ssl_cert)) and |
424 | - not all((ssl_key, ssl_cert))): |
425 | - log('If ssl_key or ssl_cert are specified both are required.', |
426 | - level=ERROR) |
427 | - sys.exit(1) |
428 | - |
429 | - if not external_ca: |
430 | - ssl_cert, ssl_key, ssl_ca = ServiceCA.get_service_cert() |
431 | - |
432 | - rabbit.enable_ssl( |
433 | - ssl_key, ssl_cert, ssl_port, ssl_ca, |
434 | - ssl_only=(ssl_mode == "only"), ssl_client=False) |
435 | - reconfigure_client_ssl(True) |
436 | - open_port(ssl_port) |
437 | - |
438 | - |
439 | @hooks.hook('config-changed') |
440 | @restart_on_change(rabbit.restart_map()) |
441 | def config_changed(): |
442 | + |
443 | if config('prefer-ipv6'): |
444 | rabbit.assert_charm_supports_ipv6() |
445 | |
446 | @@ -652,9 +546,9 @@ |
447 | rabbit.disable_plugin(MAN_PLUGIN) |
448 | close_port(55672) |
449 | |
450 | - configure_rabbit_ssl() |
451 | - |
452 | rabbit.set_all_mirroring_queues(config('mirroring-queues')) |
453 | + rabbit.ConfigRenderer( |
454 | + rabbit.CONFIG_FILES).write_all() |
455 | |
456 | if is_relation_made("ha"): |
457 | ha_is_active_active = config("ha-vip-only") |
458 | |
459 | === added file 'hooks/ssl_utils.py' |
460 | --- hooks/ssl_utils.py 1970-01-01 00:00:00 +0000 |
461 | +++ hooks/ssl_utils.py 2015-04-10 02:40:31 +0000 |
462 | @@ -0,0 +1,55 @@ |
463 | +from charmhelpers.contrib.ssl.service import ServiceCA |
464 | + |
465 | +from charmhelpers.core.hookenv import ( |
466 | + config, |
467 | + relation_ids, |
468 | + relation_set, |
469 | + relation_get, |
470 | +) |
471 | + |
472 | +import base64 |
473 | +import os |
474 | + |
475 | + |
476 | +def get_ssl_mode(): |
477 | + ssl_mode = config('ssl') |
478 | + external_ca = False |
479 | + # Legacy config boolean option |
480 | + ssl_on = config('ssl_enabled') |
481 | + if ssl_mode == 'off' and ssl_on is False: |
482 | + ssl_mode = 'off' |
483 | + elif ssl_mode == 'off' and ssl_on: |
484 | + ssl_mode = 'on' |
485 | + ssl_key = config('ssl_key') |
486 | + ssl_cert = config('ssl_cert') |
487 | + if all((ssl_key, ssl_cert)): |
488 | + external_ca = True |
489 | + return ssl_mode, external_ca |
490 | + |
491 | + |
492 | +def configure_client_ssl(relation_data): |
493 | + """Configure client with ssl |
494 | + """ |
495 | + ssl_mode, external_ca = get_ssl_mode() |
496 | + if ssl_mode == 'off': |
497 | + return |
498 | + relation_data['ssl_port'] = config('ssl_port') |
499 | + if external_ca: |
500 | + if config('ssl_ca'): |
501 | + relation_data['ssl_ca'] = base64.b64encode( |
502 | + config('ssl_ca')) |
503 | + return |
504 | + ca = ServiceCA.get_ca() |
505 | + relation_data['ssl_ca'] = base64.b64encode(ca.get_ca_bundle()) |
506 | + |
507 | + |
508 | +def reconfigure_client_ssl(ssl_enabled=False): |
509 | + ssl_config_keys = set(('ssl_key', 'ssl_cert', 'ssl_ca')) |
510 | + for rid in relation_ids('amqp'): |
511 | + rdata = relation_get(rid=rid, unit=os.environ['JUJU_UNIT_NAME']) |
512 | + if not ssl_enabled and ssl_config_keys.intersection(rdata): |
513 | + # No clean way to remove entirely, but blank them. |
514 | + relation_set(relation_id=rid, ssl_key='', ssl_cert='', ssl_ca='') |
515 | + elif ssl_enabled and not ssl_config_keys.intersection(rdata): |
516 | + configure_client_ssl(rdata) |
517 | + relation_set(relation_id=rid, **rdata) |
518 | |
519 | === modified file 'templates/rabbitmq.config' |
520 | --- templates/rabbitmq.config 2014-05-23 08:13:05 +0000 |
521 | +++ templates/rabbitmq.config 2015-04-10 02:40:31 +0000 |
522 | @@ -1,21 +1,35 @@ |
523 | [ |
524 | - {rabbit, [ |
525 | -{% if ssl_only %} |
526 | + {rabbit, [ |
527 | +{% if ssl_only %} |
528 | {tcp_listeners, []}, |
529 | {% else %} |
530 | {tcp_listeners, [5672]}, |
531 | {% endif %} |
532 | - {ssl_listeners, [{{ ssl_port }}]}, |
533 | +{% if ssl_port %} |
534 | + {ssl_listeners, [{{ ssl_port }}]}, |
535 | +{% endif %} |
536 | +{% if ssl_mode == "on" %} |
537 | {ssl_options, [ |
538 | {verify, verify_peer}, |
539 | -{% if ssl_client %} |
540 | - {fail_if_no_peer_cert, true}, |
541 | +{% if ssl_client %} |
542 | + {fail_if_no_peer_cert, true}, |
543 | {% else %} |
544 | {fail_if_no_peer_cert, false}, |
545 | -{% endif %}{% if ssl_ca_file %} |
546 | - {cacertfile, "{{ ssl_ca_file }}"}, {% endif %} |
547 | - {certfile, "{{ ssl_cert_file }}"}, |
548 | - {keyfile, "{{ ssl_key_file }}"} |
549 | - ]} |
550 | +{% endif %} |
551 | + {% if ssl_ca_file %} |
552 | + {cacertfile, "{{ ssl_ca_file }}"}, |
553 | + {% endif %} |
554 | + {% if ssl_cert_file %} |
555 | + {certfile, "{{ ssl_cert_file }}"}, |
556 | + {% endif %} |
557 | + {% if ssl_key_file %} |
558 | + {keyfile, "{{ ssl_key_file }}"} |
559 | + {% endif %} |
560 | + ]}, |
561 | +{% endif %} |
562 | + |
563 | + {% if cluster_partition_handling %} |
564 | + {cluster_partition_handling, {{ cluster_partition_handling }}} |
565 | + {% endif %} |
566 | ]} |
567 | -]. |
568 | \ No newline at end of file |
569 | +]. |
570 | |
571 | === modified file 'tests/00_setup.sh' |
572 | --- tests/00_setup.sh 2015-03-12 16:42:09 +0000 |
573 | +++ tests/00_setup.sh 2015-04-10 02:40:31 +0000 |
574 | @@ -15,4 +15,7 @@ |
575 | # Install any additional python packages, or software here. |
576 | sudo apt-get install -y python python-pika python3-requests python3-setuptools |
577 | |
578 | +# Set http proxy if amulet is using one. |
579 | +[[ -n "$AMULET_HTTP_PROXY" ]] && export http_proxy="$AMULET_HTTP_PROXY" && https_proxy="$AMULET_HTTP_PROXY" |
580 | + |
581 | sudo easy_install3 python3-pika |
582 | |
583 | === added file 'tests/50_test_cluster_partition.py' |
584 | --- tests/50_test_cluster_partition.py 1970-01-01 00:00:00 +0000 |
585 | +++ tests/50_test_cluster_partition.py 2015-04-10 02:40:31 +0000 |
586 | @@ -0,0 +1,31 @@ |
587 | +#!/usr/bin/python |
588 | +# |
589 | +# This Amulet test deploys rabbitmq-server |
590 | +# |
591 | +# Note: We use python2, because pika doesn't support python3 |
592 | +import amulet |
593 | + |
594 | +# The number of seconds to wait for the environment to setup. |
595 | +seconds = 1200 |
596 | +d = amulet.Deployment(series="trusty") |
597 | + |
598 | +d.add('rabbitmq-server', units=1) |
599 | +# Create a configuration. |
600 | +configuration = {'cluster-partition-handling': "autoheal"} |
601 | +d.configure('rabbitmq-server', configuration) |
602 | + |
603 | +d.expose('rabbitmq-server') |
604 | +try: |
605 | + d.setup(timeout=seconds) |
606 | + d.sentry.wait(seconds) |
607 | +except amulet.helpers.TimeoutError: |
608 | + message = 'The environment did not setup in %d seconds.' % seconds |
609 | + amulet.raise_status(amulet.SKIP, msg=message) |
610 | +except: |
611 | + raise |
612 | + |
613 | +rabbit_unit = d.sentry.unit['rabbitmq-server/0'] |
614 | +output, code = rabbit_unit.run("grep autoheal /etc/rabbitmq/rabbitmq.conf") |
615 | + |
616 | +if code != 0 or output == "": |
617 | + amulet.raise_status(amulet.FAIL, msg=message) |
618 | |
619 | === modified file 'unit_tests/test_rabbit_utils.py' |
620 | --- unit_tests/test_rabbit_utils.py 2014-10-08 15:57:57 +0000 |
621 | +++ unit_tests/test_rabbit_utils.py 2015-04-10 02:40:31 +0000 |
622 | @@ -4,8 +4,8 @@ |
623 | import tempfile |
624 | import sys |
625 | |
626 | +import rabbit_utils |
627 | sys.modules['MySQLdb'] = mock.Mock() |
628 | -import rabbit_utils |
629 | |
630 | |
631 | class UtilsTests(unittest.TestCase): |
632 | |
633 | === added file 'unit_tests/test_rabbitmq_context.py' |
634 | --- unit_tests/test_rabbitmq_context.py 1970-01-01 00:00:00 +0000 |
635 | +++ unit_tests/test_rabbitmq_context.py 2015-04-10 02:40:31 +0000 |
636 | @@ -0,0 +1,79 @@ |
637 | +import rabbitmq_context |
638 | + |
639 | +import mock |
640 | +import unittest |
641 | + |
642 | + |
643 | +class TestRabbitMQSSLContext(unittest.TestCase): |
644 | + |
645 | + @mock.patch("rabbitmq_context.config") |
646 | + @mock.patch("rabbitmq_context.close_port") |
647 | + @mock.patch("rabbitmq_context.ssl_utils.reconfigure_client_ssl") |
648 | + @mock.patch("rabbitmq_context.ssl_utils.get_ssl_mode") |
649 | + def test_context_ssl_off(self, get_ssl_mode, reconfig_ssl, close_port, |
650 | + config): |
651 | + get_ssl_mode.return_value = ("off", "off") |
652 | + self.assertEqual(rabbitmq_context.RabbitMQSSLContext().__call__(), { |
653 | + "ssl_mode": "off" |
654 | + }) |
655 | + |
656 | + close_port.assert_called_once() |
657 | + reconfig_ssl.assert_called_once() |
658 | + |
659 | + @mock.patch("rabbitmq_context.open_port") |
660 | + @mock.patch("rabbitmq_context.os.chmod") |
661 | + @mock.patch("rabbitmq_context.os.chown") |
662 | + @mock.patch("rabbitmq_context.pwd.getpwnam") |
663 | + @mock.patch("rabbitmq_context.grp.getgrnam") |
664 | + @mock.patch("rabbitmq_context.config") |
665 | + @mock.patch("rabbitmq_context.close_port") |
666 | + @mock.patch("rabbitmq_context.ssl_utils.reconfigure_client_ssl") |
667 | + @mock.patch("rabbitmq_context.ssl_utils.get_ssl_mode") |
668 | + def test_context_ssl_on(self, get_ssl_mode, reconfig_ssl, close_port, |
669 | + config, gr, pw, chown, chmod, open_port): |
670 | + |
671 | + get_ssl_mode.return_value = ("on", "on") |
672 | + |
673 | + def config_get(n): |
674 | + return None |
675 | + |
676 | + config.side_effect = config_get |
677 | + |
678 | + def pw(name): |
679 | + class Uid(object): |
680 | + pw_uid = 1 |
681 | + gr_gid = 100 |
682 | + return Uid() |
683 | + |
684 | + pw.side_effect = pw |
685 | + gr.side_effect = pw |
686 | + |
687 | + m = mock.mock_open() |
688 | + with mock.patch('rabbitmq_context.open', m, create=True): |
689 | + self.assertEqual( |
690 | + rabbitmq_context.RabbitMQSSLContext().__call__(), { |
691 | + "ssl_port": None, |
692 | + "ssl_cert_file": "/etc/rabbitmq/rabbit-server-cert.pem", |
693 | + "ssl_key_file": '/etc/rabbitmq/rabbit-server-privkey.pem', |
694 | + "ssl_client": False, |
695 | + "ssl_ca_file": "", |
696 | + "ssl_only": False, |
697 | + "ssl_mode": "on", |
698 | + }) |
699 | + |
700 | + reconfig_ssl.assert_called_once() |
701 | + open_port.assert_called_once() |
702 | + |
703 | + |
704 | +class TestRabbitMQClusterContext(unittest.TestCase): |
705 | + |
706 | + @mock.patch("rabbitmq_context.config") |
707 | + def test_context_ssl_off(self, config): |
708 | + config.return_value = "ignore" |
709 | + |
710 | + self.assertEqual( |
711 | + rabbitmq_context.RabbitMQClusterContext().__call__(), { |
712 | + 'cluster_partition_handling': "ignore" |
713 | + }) |
714 | + |
715 | + config.assert_called_once_with("cluster-partition-handling") |
716 | |
717 | === modified file 'unit_tests/test_rabbitmq_server_relations.py' |
718 | --- unit_tests/test_rabbitmq_server_relations.py 2015-01-23 08:23:05 +0000 |
719 | +++ unit_tests/test_rabbitmq_server_relations.py 2015-04-10 02:40:31 +0000 |
720 | @@ -2,7 +2,7 @@ |
721 | from testtools import TestCase |
722 | from mock import patch, MagicMock |
723 | |
724 | -os.environ['JUJU_UNIT_NAME'] = 'UNIT_TEST/0' |
725 | +os.environ['JUJU_UNIT_NAME'] = 'UNIT_TEST/0' # noqa - needed for import |
726 | import rabbitmq_server_relations |
727 | |
728 | |
729 | @@ -37,7 +37,7 @@ |
730 | @patch('rabbitmq_server_relations.relation_set') |
731 | @patch('apt_pkg.Cache') |
732 | @patch('rabbitmq_server_relations.is_clustered') |
733 | - @patch('rabbitmq_server_relations.configure_client_ssl') |
734 | + @patch('rabbitmq_server_relations.ssl_utils.configure_client_ssl') |
735 | @patch('rabbitmq_server_relations.unit_get') |
736 | @patch('rabbitmq_server_relations.relation_get') |
737 | @patch('rabbitmq_server_relations.is_elected_leader') |
738 | @@ -87,7 +87,7 @@ |
739 | @patch('rabbitmq_server_relations.relation_set') |
740 | @patch('apt_pkg.Cache') |
741 | @patch('rabbitmq_server_relations.is_clustered') |
742 | - @patch('rabbitmq_server_relations.configure_client_ssl') |
743 | + @patch('rabbitmq_server_relations.ssl_utils.configure_client_ssl') |
744 | @patch('rabbitmq_server_relations.unit_get') |
745 | @patch('rabbitmq_server_relations.relation_get') |
746 | @patch('rabbitmq_server_relations.is_elected_leader') |
Jorge,
I think some of the refactor in here is a definite improvement and makes things cleaner, thanks! I've got a few inline comments included, but the biggest thing is that the rabbitmq-server charm now has a /next and /trunk branch to match the rest of the flow of the openstack charms (since this has recently come under ownership of the ~openstack-charmers team). Can you retarget for /next?
Also, I think the README file should be updated with some discussions regarding high availability.
I'll run through some tests on this but wanted to drop some feedback now.