Merge lp:~niedbalski/charms/trusty/rabbitmq-server/fix-1442443 into lp:~openstack-charmers-archive/charms/trusty/rabbitmq-server/next

Proposed by Jorge Niedbalski
Status: Superseded
Proposed branch: lp:~niedbalski/charms/trusty/rabbitmq-server/fix-1442443
Merge into: lp:~openstack-charmers-archive/charms/trusty/rabbitmq-server/next
Diff against target: 707 lines (+392/-152)
9 files modified
config.yaml (+23/-1)
hooks/rabbit_utils.py (+37/-39)
hooks/rabbitmq_context.py (+122/-0)
hooks/rabbitmq_server_relations.py (+7/-99)
hooks/ssl_utils.py (+66/-0)
templates/rabbitmq.config (+25/-11)
tests/50_test_cluster_partition.py (+31/-0)
unit_tests/test_rabbitmq_context.py (+79/-0)
unit_tests/test_rabbitmq_server_relations.py (+2/-2)
To merge this branch: bzr merge lp:~niedbalski/charms/trusty/rabbitmq-server/fix-1442443
Reviewer Review Type Date Requested Status
James Page Needs Fixing
Billy Olsen Pending
Review via email: mp+255872@code.launchpad.net

This proposal supersedes a proposal from 2015-04-10.

This proposal has been superseded by a proposal from 2015-04-16.

Description of the change

- Added the cluster_partition_handling option fixes LP: #1442443
- Refactored the ssl handling code.
- Added a generic config loader

To post a comment you must log in.
Revision history for this message
Billy Olsen (billy-olsen) wrote : Posted in a previous version of this proposal

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.

review: Needs Fixing
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_lint_check #3202 rabbitmq-server for niedbalski mp255770
    LINT OK: passed

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_unit_test #2990 rabbitmq-server for niedbalski mp255770
    UNIT OK: passed

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

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://paste.ubuntu.com/10789138/
Build: http://10.245.162.77:8080/job/charm_amulet_test/3019/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_lint_check #3210 rabbitmq-server-next for niedbalski mp255820
    LINT OK: passed

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_unit_test #2998 rabbitmq-server-next for niedbalski mp255820
    UNIT OK: passed

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_amulet_test #3027 rabbitmq-server-next for niedbalski mp255820
    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://paste.ubuntu.com/10791489/
Build: http://10.245.162.77:8080/job/charm_amulet_test/3027/

Revision history for this message
Edward Hope-Morley (hopem) : Posted in a previous version of this proposal
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_unit_test #3005 rabbitmq-server-next for niedbalski mp255820
    UNIT OK: passed

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : Posted in a previous version of this proposal

charm_lint_check #3217 rabbitmq-server-next for niedbalski mp255820
    LINT OK: passed

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

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

charm_lint_check #3224 rabbitmq-server-next for niedbalski mp255872
    LINT OK: passed

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

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

charm_unit_test #3012 rabbitmq-server-next for niedbalski mp255872
    UNIT OK: passed

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

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

charm_amulet_test #3041 rabbitmq-server-next for niedbalski mp255872
    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://paste.ubuntu.com/10795233/
Build: http://10.245.162.77:8080/job/charm_amulet_test/3041/

Revision history for this message
James Page (james-page) wrote :

Please can you review the amulet test failures - they appear to be related to SSL.

review: Needs Fixing
Revision history for this message
Jorge Niedbalski (niedbalski) wrote :

@james-page:

Seems that this tests has been failing since Feb 23 (I tested rev 86), because the certificates being used in amulet tests expired:

verify error:num=10:certificate has expired
notAfter=Feb 23 20:08:18 2015 GMT

This is not directly implied to my proposed change, and seems that https://bugs.launchpad.net/charms/+source/rabbitmq-server/+bug/1436014 is already keeping track of this.

I would appreciate if you can review this proposal.

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

charm_unit_test #3086 rabbitmq-server-next for niedbalski mp255872
    UNIT OK: passed

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

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

charm_lint_check #3298 rabbitmq-server-next for niedbalski mp255872
    LINT OK: passed

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

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

charm_amulet_test #3115 rabbitmq-server-next for niedbalski mp255872
    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://paste.ubuntu.com/10817321/
Build: http://10.245.162.77:8080/job/charm_amulet_test/3115/

Revision history for this message
Billy Olsen (billy-olsen) wrote :

With these changes, this LGTM. I tested some of the partitioning logic here and things seem fine by me. It appears that an unknown value for cluster_partition_handling is treated as ignore which might be confusing for someone if they weren't expecting that, but its hard to predict what the future holds.

The fix for LP#1436014 is already in the queue and I don't think it should particularly hold this up, however osci bails as soon as the first test fails and I can't see the full output.

I'm running the amulet tests against your change + the fix for 1436014 and will mark it based on the findings of that.

As always, thanks for the submission Jorge!

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'config.yaml'
--- config.yaml 2015-03-03 06:05:14 +0000
+++ config.yaml 2015-04-13 17:16:27 +0000
@@ -8,7 +8,7 @@
8 type: string8 type: string
9 default: "off"9 default: "off"
10 description: |10 description: |
11 Enable SSL connections on rabbitmq, valid values are 'off', 'on', 'only'. If ssl_key, 11 Enable SSL connections on rabbitmq, valid values are 'off', 'on', 'only'. If ssl_key,
12 ssl_cert, ssl_ca are provided then then those values will be used. Otherwise12 ssl_cert, ssl_ca are provided then then those values will be used. Otherwise
13 the service will act as its own certificate authority and pass its ca cert to clients.13 the service will act as its own certificate authority and pass its ca cert to clients.
14 For HA or clustered rabbits ssl key/cert must be provided.14 For HA or clustered rabbits ssl key/cert must be provided.
@@ -92,6 +92,28 @@
92 description: |92 description: |
93 When set to true the 'ha-mode: all' policy is applied to all the exchages93 When set to true the 'ha-mode: all' policy is applied to all the exchages
94 that match the expression '^(?!amq\.).*'94 that match the expression '^(?!amq\.).*'
95 cluster-partition-handling:
96 type: string
97 default: ignore
98 description: |
99 RabbitMQ offers three ways to deal with network partitions automatically.
100 Available modes:
101
102 ignore - Your network is reliable. All your nodes are in a rack,
103 connected with a switch, and that switch is also the route to the outside world.
104 You don't want to run any risk of any of your cluster shutting down if any other part of it fails
105 (or you have a two node cluster).
106
107 pause_minority - Your network is maybe less reliable. You have clustered across 3 AZs in EC2,
108 and you assume that only one AZ will fail at once.
109 In that scenario you want the remaining two AZs to continue working and the nodes from the failed AZ
110 to rejoin automatically and without fuss when the AZ comes back.
111
112 autoheal - Your network may not be reliable.
113 You are more concerned with continuity of service than with data integrity.
114 You may have a two node cluster.
115
116 For more information see http://www.rabbitmq.com/partitions.html.
95 rbd-size:117 rbd-size:
96 type: string118 type: string
97 default: 5G119 default: 5G
98120
=== modified file 'hooks/rabbit_utils.py'
--- hooks/rabbit_utils.py 2015-03-26 13:07:43 +0000
+++ hooks/rabbit_utils.py 2015-04-13 17:16:27 +0000
@@ -1,6 +1,4 @@
1import os1import os
2import pwd
3import grp
4import re2import re
5import socket3import socket
6import sys4import sys
@@ -8,6 +6,13 @@
8import glob6import glob
9import tempfile7import tempfile
108
9from rabbitmq_context import (
10 RabbitMQSSLContext,
11 RabbitMQClusterContext
12)
13
14from charmhelpers.core.templating import render
15
11from charmhelpers.contrib.openstack.utils import (16from charmhelpers.contrib.openstack.utils import (
12 get_hostname,17 get_hostname,
13)18)
@@ -30,8 +35,6 @@
30 cmp_pkgrevno35 cmp_pkgrevno
31)36)
3237
33from charmhelpers.core.templating import render
34
35from charmhelpers.contrib.peerstorage import (38from charmhelpers.contrib.peerstorage import (
36 peer_store,39 peer_store,
37 peer_retrieve40 peer_retrieve
@@ -57,7 +60,10 @@
57# the charm doesn't concern itself with template specifics etc.60# the charm doesn't concern itself with template specifics etc.
58CONFIG_FILES = OrderedDict([61CONFIG_FILES = OrderedDict([
59 (RABBITMQ_CONF, {62 (RABBITMQ_CONF, {
60 'hook_contexts': None,63 'hook_contexts': [
64 RabbitMQSSLContext(),
65 RabbitMQClusterContext(),
66 ],
61 'services': ['rabbitmq-server']67 'services': ['rabbitmq-server']
62 }),68 }),
63 (ENV_CONF, {69 (ENV_CONF, {
@@ -71,6 +77,32 @@
71])77])
7278
7379
80class ConfigRenderer():
81
82 def __init__(self, config):
83 self.config_data = {}
84
85 for config_path, data in config.items():
86 if 'hook_contexts' in data and data['hook_contexts']:
87 ctxt = {}
88 for svc_context in data['hook_contexts']:
89 ctxt.update(svc_context())
90 self.config_data[config_path] = ctxt
91
92 def write(self, config_path):
93 data = self.config_data.get(config_path, None)
94 if data:
95 log("writing config file: %s , data: %s" % (config_path,
96 str(data)), level='DEBUG')
97
98 render(os.path.basename(config_path), config_path,
99 data, perms=0o644)
100
101 def write_all(self):
102 for service in self.config_data.keys():
103 self.write(service)
104
105
74class RabbitmqError(Exception):106class RabbitmqError(Exception):
75 pass107 pass
76108
@@ -390,40 +422,6 @@
390def disable_plugin(plugin):422def disable_plugin(plugin):
391 _manage_plugin(plugin, 'disable')423 _manage_plugin(plugin, 'disable')
392424
393ssl_key_file = "/etc/rabbitmq/rabbit-server-privkey.pem"
394ssl_cert_file = "/etc/rabbitmq/rabbit-server-cert.pem"
395ssl_ca_file = "/etc/rabbitmq/rabbit-server-ca.pem"
396
397
398def enable_ssl(ssl_key, ssl_cert, ssl_port,
399 ssl_ca=None, ssl_only=False, ssl_client=None):
400 uid = pwd.getpwnam("root").pw_uid
401 gid = grp.getgrnam("rabbitmq").gr_gid
402
403 for contents, path in (
404 (ssl_key, ssl_key_file),
405 (ssl_cert, ssl_cert_file),
406 (ssl_ca, ssl_ca_file)):
407 if not contents:
408 continue
409 with open(path, 'w') as fh:
410 fh.write(contents)
411 os.chmod(path, 0o640)
412 os.chown(path, uid, gid)
413
414 data = {
415 "ssl_port": ssl_port,
416 "ssl_cert_file": ssl_cert_file,
417 "ssl_key_file": ssl_key_file,
418 "ssl_client": ssl_client,
419 "ssl_ca_file": "",
420 "ssl_only": ssl_only}
421
422 if ssl_ca:
423 data["ssl_ca_file"] = ssl_ca_file
424
425 render(os.path.basename(RABBITMQ_CONF), RABBITMQ_CONF, data, perms=0o644)
426
427425
428def execute(cmd, die=False, echo=False):426def execute(cmd, die=False, echo=False):
429 """ Executes a command427 """ Executes a command
430428
=== added file 'hooks/rabbitmq_context.py'
--- hooks/rabbitmq_context.py 1970-01-01 00:00:00 +0000
+++ hooks/rabbitmq_context.py 2015-04-13 17:16:27 +0000
@@ -0,0 +1,122 @@
1from charmhelpers.contrib.ssl.service import ServiceCA
2
3from charmhelpers.core.hookenv import (
4 open_port,
5 close_port,
6 config,
7 log,
8 ERROR,
9)
10
11import sys
12import pwd
13import grp
14import os
15import base64
16
17import ssl_utils
18
19ssl_key_file = "/etc/rabbitmq/rabbit-server-privkey.pem"
20ssl_cert_file = "/etc/rabbitmq/rabbit-server-cert.pem"
21ssl_ca_file = "/etc/rabbitmq/rabbit-server-ca.pem"
22
23
24def convert_from_base64(v):
25 # Rabbit originally supported pem encoded key/cert in config, play
26 # nice on upgrades as we now expect base64 encoded key/cert/ca.
27 if not v:
28 return v
29 if v.startswith('-----BEGIN'):
30 return v
31 try:
32 return base64.b64decode(v)
33 except TypeError:
34 return v
35
36
37class RabbitMQSSLContext(object):
38
39 def enable_ssl(self, ssl_key, ssl_cert, ssl_port,
40 ssl_ca=None, ssl_only=False, ssl_client=None):
41
42 uid = pwd.getpwnam("root").pw_uid
43 gid = grp.getgrnam("rabbitmq").gr_gid
44
45 for contents, path in (
46 (ssl_key, ssl_key_file),
47 (ssl_cert, ssl_cert_file),
48 (ssl_ca, ssl_ca_file)):
49
50 if not contents:
51 continue
52
53 with open(path, 'w') as fh:
54 fh.write(contents)
55
56 os.chmod(path, 0o640)
57 os.chown(path, uid, gid)
58
59 data = {
60 "ssl_port": ssl_port,
61 "ssl_cert_file": ssl_cert_file,
62 "ssl_key_file": ssl_key_file,
63 "ssl_client": ssl_client,
64 "ssl_ca_file": "",
65 "ssl_only": ssl_only
66 }
67
68 if ssl_ca:
69 data["ssl_ca_file"] = ssl_ca_file
70
71 return data
72
73 def __call__(self):
74 """
75 The legacy config support adds some additional complications.
76
77 ssl_enabled = True, ssl = off -> ssl enabled
78 ssl_enabled = False, ssl = on -> ssl enabled
79 """
80 ssl_mode, external_ca = ssl_utils.get_ssl_mode()
81
82 ctxt = {
83 'ssl_mode': ssl_mode,
84 }
85
86 if ssl_mode == 'off':
87 close_port(config('ssl_port'))
88 ssl_utils.reconfigure_client_ssl()
89 return ctxt
90
91 ssl_key = convert_from_base64(config('ssl_key'))
92 ssl_cert = convert_from_base64(config('ssl_cert'))
93 ssl_ca = convert_from_base64(config('ssl_ca'))
94 ssl_port = config('ssl_port')
95
96 # If external managed certs then we need all the fields.
97 if (ssl_mode in ('on', 'only') and any((ssl_key, ssl_cert)) and
98 not all((ssl_key, ssl_cert))):
99 log('If ssl_key or ssl_cert are specified both are required.',
100 level=ERROR)
101 sys.exit(1)
102
103 if not external_ca:
104 ssl_cert, ssl_key, ssl_ca = ServiceCA.get_service_cert()
105
106 ctxt.update(self.enable_ssl(
107 ssl_key, ssl_cert, ssl_port, ssl_ca,
108 ssl_only=(ssl_mode == "only"), ssl_client=False
109 ))
110
111 ssl_utils.reconfigure_client_ssl(True)
112 open_port(ssl_port)
113
114 return ctxt
115
116
117class RabbitMQClusterContext(object):
118
119 def __call__(self):
120 return {
121 'cluster_partition_handling': config('cluster-partition-handling'),
122 }
0123
=== modified file 'hooks/rabbitmq_server_relations.py'
--- hooks/rabbitmq_server_relations.py 2015-04-01 09:33:46 +0000
+++ hooks/rabbitmq_server_relations.py 2015-04-13 17:16:27 +0000
@@ -1,5 +1,5 @@
1#!/usr/bin/python1#!/usr/bin/python
2import base642
3import os3import os
4import shutil4import shutil
5import sys5import sys
@@ -8,6 +8,8 @@
8import socket8import socket
99
10import rabbit_utils as rabbit10import rabbit_utils as rabbit
11import ssl_utils
12
11from lib.utils import (13from lib.utils import (
12 chown, chmod,14 chown, chmod,
13 is_newer,15 is_newer,
@@ -60,7 +62,6 @@
60 service_restart,62 service_restart,
61)63)
62from charmhelpers.contrib.charmsupport import nrpe64from charmhelpers.contrib.charmsupport import nrpe
63from charmhelpers.contrib.ssl.service import ServiceCA
6465
65from charmhelpers.contrib.peerstorage import (66from charmhelpers.contrib.peerstorage import (
66 peer_echo,67 peer_echo,
@@ -175,7 +176,7 @@
175 get_address_in_network(config('access-network'),176 get_address_in_network(config('access-network'),
176 unit_get('private-address'))177 unit_get('private-address'))
177178
178 configure_client_ssl(relation_settings)179 ssl_utils.configure_client_ssl(relation_settings)
179180
180 if is_clustered():181 if is_clustered():
181 relation_settings['clustered'] = 'true'182 relation_settings['clustered'] = 'true'
@@ -512,103 +513,10 @@
512MAN_PLUGIN = 'rabbitmq_management'513MAN_PLUGIN = 'rabbitmq_management'
513514
514515
515def configure_client_ssl(relation_data):
516 """Configure client with ssl
517 """
518 ssl_mode, external_ca = _get_ssl_mode()
519 if ssl_mode == 'off':
520 return
521 relation_data['ssl_port'] = config('ssl_port')
522 if external_ca:
523 if config('ssl_ca'):
524 relation_data['ssl_ca'] = base64.b64encode(
525 config('ssl_ca'))
526 return
527 ca = ServiceCA.get_ca()
528 relation_data['ssl_ca'] = base64.b64encode(ca.get_ca_bundle())
529
530
531def _get_ssl_mode():
532 ssl_mode = config('ssl')
533 external_ca = False
534 # Legacy config boolean option
535 ssl_on = config('ssl_enabled')
536 if ssl_mode == 'off' and ssl_on is False:
537 ssl_mode = 'off'
538 elif ssl_mode == 'off' and ssl_on:
539 ssl_mode = 'on'
540 ssl_key = config('ssl_key')
541 ssl_cert = config('ssl_cert')
542 if all((ssl_key, ssl_cert)):
543 external_ca = True
544 return ssl_mode, external_ca
545
546
547def _convert_from_base64(v):
548 # Rabbit originally supported pem encoded key/cert in config, play
549 # nice on upgrades as we now expect base64 encoded key/cert/ca.
550 if not v:
551 return v
552 if v.startswith('-----BEGIN'):
553 return v
554 try:
555 return base64.b64decode(v)
556 except TypeError:
557 return v
558
559
560def reconfigure_client_ssl(ssl_enabled=False):
561 ssl_config_keys = set(('ssl_key', 'ssl_cert', 'ssl_ca'))
562 for rid in relation_ids('amqp'):
563 rdata = relation_get(rid=rid, unit=os.environ['JUJU_UNIT_NAME'])
564 if not ssl_enabled and ssl_config_keys.intersection(rdata):
565 # No clean way to remove entirely, but blank them.
566 relation_set(relation_id=rid, ssl_key='', ssl_cert='', ssl_ca='')
567 elif ssl_enabled and not ssl_config_keys.intersection(rdata):
568 configure_client_ssl(rdata)
569 relation_set(relation_id=rid, **rdata)
570
571
572def configure_rabbit_ssl():
573 """
574 The legacy config support adds some additional complications.
575
576 ssl_enabled = True, ssl = off -> ssl enabled
577 ssl_enabled = False, ssl = on -> ssl enabled
578 """
579 ssl_mode, external_ca = _get_ssl_mode()
580
581 if ssl_mode == 'off':
582 if os.path.exists(rabbit.RABBITMQ_CONF):
583 os.remove(rabbit.RABBITMQ_CONF)
584 close_port(config('ssl_port'))
585 reconfigure_client_ssl()
586 return
587 ssl_key = _convert_from_base64(config('ssl_key'))
588 ssl_cert = _convert_from_base64(config('ssl_cert'))
589 ssl_ca = _convert_from_base64(config('ssl_ca'))
590 ssl_port = config('ssl_port')
591
592 # If external managed certs then we need all the fields.
593 if (ssl_mode in ('on', 'only') and any((ssl_key, ssl_cert)) and
594 not all((ssl_key, ssl_cert))):
595 log('If ssl_key or ssl_cert are specified both are required.',
596 level=ERROR)
597 sys.exit(1)
598
599 if not external_ca:
600 ssl_cert, ssl_key, ssl_ca = ServiceCA.get_service_cert()
601
602 rabbit.enable_ssl(
603 ssl_key, ssl_cert, ssl_port, ssl_ca,
604 ssl_only=(ssl_mode == "only"), ssl_client=False)
605 reconfigure_client_ssl(True)
606 open_port(ssl_port)
607
608
609@hooks.hook('config-changed')516@hooks.hook('config-changed')
610@restart_on_change(rabbit.restart_map())517@restart_on_change(rabbit.restart_map())
611def config_changed():518def config_changed():
519
612 if config('prefer-ipv6'):520 if config('prefer-ipv6'):
613 rabbit.assert_charm_supports_ipv6()521 rabbit.assert_charm_supports_ipv6()
614522
@@ -638,9 +546,9 @@
638 rabbit.disable_plugin(MAN_PLUGIN)546 rabbit.disable_plugin(MAN_PLUGIN)
639 close_port(55672)547 close_port(55672)
640548
641 configure_rabbit_ssl()
642
643 rabbit.set_all_mirroring_queues(config('mirroring-queues'))549 rabbit.set_all_mirroring_queues(config('mirroring-queues'))
550 rabbit.ConfigRenderer(
551 rabbit.CONFIG_FILES).write_all()
644552
645 if is_relation_made("ha"):553 if is_relation_made("ha"):
646 ha_is_active_active = config("ha-vip-only")554 ha_is_active_active = config("ha-vip-only")
647555
=== added file 'hooks/ssl_utils.py'
--- hooks/ssl_utils.py 1970-01-01 00:00:00 +0000
+++ hooks/ssl_utils.py 2015-04-13 17:16:27 +0000
@@ -0,0 +1,66 @@
1from charmhelpers.contrib.ssl.service import ServiceCA
2
3from charmhelpers.core.hookenv import (
4 config,
5 relation_ids,
6 relation_set,
7 relation_get,
8 log,
9 WARNING,
10 local_unit,
11)
12
13import base64
14
15
16def get_ssl_mode():
17 ssl_mode = config('ssl')
18 external_ca = False
19 # Legacy config boolean option
20 ssl_enabled = config('ssl_enabled')
21
22 if ssl_enabled:
23 log("Deprecated ssl_enabled config option is True -\
24 this should be set to False and 'ssl' config set to 'on' instead.",
25 level=WARNING)
26 ssl_mode = 'on'
27 elif ssl_mode == 'on':
28 ssl_mode = 'on'
29 else:
30 ssl_mode = 'off'
31
32 ssl_key = config('ssl_key')
33 ssl_cert = config('ssl_cert')
34
35 if all((ssl_key, ssl_cert)):
36 external_ca = True
37
38 return ssl_mode, external_ca
39
40
41def configure_client_ssl(relation_data):
42 """Configure client with ssl
43 """
44 ssl_mode, external_ca = get_ssl_mode()
45 if ssl_mode == 'off':
46 return
47 relation_data['ssl_port'] = config('ssl_port')
48 if external_ca:
49 if config('ssl_ca'):
50 relation_data['ssl_ca'] = base64.b64encode(
51 config('ssl_ca'))
52 return
53 ca = ServiceCA.get_ca()
54 relation_data['ssl_ca'] = base64.b64encode(ca.get_ca_bundle())
55
56
57def reconfigure_client_ssl(ssl_enabled=False):
58 ssl_config_keys = set(('ssl_key', 'ssl_cert', 'ssl_ca'))
59 for rid in relation_ids('amqp'):
60 rdata = relation_get(rid=rid, unit=local_unit())
61 if not ssl_enabled and ssl_config_keys.intersection(rdata):
62 # No clean way to remove entirely, but blank them.
63 relation_set(relation_id=rid, ssl_key='', ssl_cert='', ssl_ca='')
64 elif ssl_enabled and not ssl_config_keys.intersection(rdata):
65 configure_client_ssl(rdata)
66 relation_set(relation_id=rid, **rdata)
067
=== modified file 'templates/rabbitmq.config'
--- templates/rabbitmq.config 2014-05-23 08:13:05 +0000
+++ templates/rabbitmq.config 2015-04-13 17:16:27 +0000
@@ -1,21 +1,35 @@
1[1[
2 {rabbit, [ 2 {rabbit, [
3{% if ssl_only %} 3{% if ssl_only %}
4 {tcp_listeners, []},4 {tcp_listeners, []},
5{% else %}5{% else %}
6 {tcp_listeners, [5672]},6 {tcp_listeners, [5672]},
7{% endif %}7{% endif %}
8 {ssl_listeners, [{{ ssl_port }}]},8{% if ssl_port %}
9 {ssl_listeners, [{{ ssl_port }}]},
10{% endif %}
11{% if ssl_mode == "on" %}
9 {ssl_options, [12 {ssl_options, [
10 {verify, verify_peer},13 {verify, verify_peer},
11{% if ssl_client %} 14{% if ssl_client %}
12 {fail_if_no_peer_cert, true}, 15 {fail_if_no_peer_cert, true},
13{% else %}16{% else %}
14 {fail_if_no_peer_cert, false},17 {fail_if_no_peer_cert, false},
15{% endif %}{% if ssl_ca_file %} 18{% endif %}
16 {cacertfile, "{{ ssl_ca_file }}"}, {% endif %}19 {% if ssl_ca_file %}
17 {certfile, "{{ ssl_cert_file }}"},20 {cacertfile, "{{ ssl_ca_file }}"},
18 {keyfile, "{{ ssl_key_file }}"}21 {% endif %}
19 ]}22 {% if ssl_cert_file %}
23 {certfile, "{{ ssl_cert_file }}"},
24 {% endif %}
25 {% if ssl_key_file %}
26 {keyfile, "{{ ssl_key_file }}"}
27 {% endif %}
28 ]},
29{% endif %}
30
31 {% if cluster_partition_handling %}
32 {cluster_partition_handling, {{ cluster_partition_handling }}}
33 {% endif %}
20 ]}34 ]}
21].
22\ No newline at end of file35\ No newline at end of file
36].
2337
=== added file 'tests/50_test_cluster_partition.py'
--- tests/50_test_cluster_partition.py 1970-01-01 00:00:00 +0000
+++ tests/50_test_cluster_partition.py 2015-04-13 17:16:27 +0000
@@ -0,0 +1,31 @@
1#!/usr/bin/python
2#
3# This Amulet test deploys rabbitmq-server
4#
5# Note: We use python2, because pika doesn't support python3
6import amulet
7
8# The number of seconds to wait for the environment to setup.
9seconds = 1200
10d = amulet.Deployment(series="trusty")
11
12d.add('rabbitmq-server', units=1)
13# Create a configuration.
14configuration = {'cluster-partition-handling': "autoheal"}
15d.configure('rabbitmq-server', configuration)
16
17d.expose('rabbitmq-server')
18try:
19 d.setup(timeout=seconds)
20 d.sentry.wait(seconds)
21except amulet.helpers.TimeoutError:
22 message = 'The environment did not setup in %d seconds.' % seconds
23 amulet.raise_status(amulet.SKIP, msg=message)
24except:
25 raise
26
27rabbit_unit = d.sentry.unit['rabbitmq-server/0']
28output, code = rabbit_unit.run("grep autoheal /etc/rabbitmq/rabbitmq.config")
29
30if code != 0 or output == "":
31 amulet.raise_status(amulet.FAIL, msg="didn't find autoheal")
032
=== added file 'unit_tests/test_rabbitmq_context.py'
--- unit_tests/test_rabbitmq_context.py 1970-01-01 00:00:00 +0000
+++ unit_tests/test_rabbitmq_context.py 2015-04-13 17:16:27 +0000
@@ -0,0 +1,79 @@
1import rabbitmq_context
2
3import mock
4import unittest
5
6
7class TestRabbitMQSSLContext(unittest.TestCase):
8
9 @mock.patch("rabbitmq_context.config")
10 @mock.patch("rabbitmq_context.close_port")
11 @mock.patch("rabbitmq_context.ssl_utils.reconfigure_client_ssl")
12 @mock.patch("rabbitmq_context.ssl_utils.get_ssl_mode")
13 def test_context_ssl_off(self, get_ssl_mode, reconfig_ssl, close_port,
14 config):
15 get_ssl_mode.return_value = ("off", "off")
16 self.assertEqual(rabbitmq_context.RabbitMQSSLContext().__call__(), {
17 "ssl_mode": "off"
18 })
19
20 close_port.assert_called_once()
21 reconfig_ssl.assert_called_once()
22
23 @mock.patch("rabbitmq_context.open_port")
24 @mock.patch("rabbitmq_context.os.chmod")
25 @mock.patch("rabbitmq_context.os.chown")
26 @mock.patch("rabbitmq_context.pwd.getpwnam")
27 @mock.patch("rabbitmq_context.grp.getgrnam")
28 @mock.patch("rabbitmq_context.config")
29 @mock.patch("rabbitmq_context.close_port")
30 @mock.patch("rabbitmq_context.ssl_utils.reconfigure_client_ssl")
31 @mock.patch("rabbitmq_context.ssl_utils.get_ssl_mode")
32 def test_context_ssl_on(self, get_ssl_mode, reconfig_ssl, close_port,
33 config, gr, pw, chown, chmod, open_port):
34
35 get_ssl_mode.return_value = ("on", "on")
36
37 def config_get(n):
38 return None
39
40 config.side_effect = config_get
41
42 def pw(name):
43 class Uid(object):
44 pw_uid = 1
45 gr_gid = 100
46 return Uid()
47
48 pw.side_effect = pw
49 gr.side_effect = pw
50
51 m = mock.mock_open()
52 with mock.patch('rabbitmq_context.open', m, create=True):
53 self.assertEqual(
54 rabbitmq_context.RabbitMQSSLContext().__call__(), {
55 "ssl_port": None,
56 "ssl_cert_file": "/etc/rabbitmq/rabbit-server-cert.pem",
57 "ssl_key_file": '/etc/rabbitmq/rabbit-server-privkey.pem',
58 "ssl_client": False,
59 "ssl_ca_file": "",
60 "ssl_only": False,
61 "ssl_mode": "on",
62 })
63
64 reconfig_ssl.assert_called_once()
65 open_port.assert_called_once()
66
67
68class TestRabbitMQClusterContext(unittest.TestCase):
69
70 @mock.patch("rabbitmq_context.config")
71 def test_context_ssl_off(self, config):
72 config.return_value = "ignore"
73
74 self.assertEqual(
75 rabbitmq_context.RabbitMQClusterContext().__call__(), {
76 'cluster_partition_handling': "ignore"
77 })
78
79 config.assert_called_once_with("cluster-partition-handling")
080
=== modified file 'unit_tests/test_rabbitmq_server_relations.py'
--- unit_tests/test_rabbitmq_server_relations.py 2015-03-03 22:59:25 +0000
+++ unit_tests/test_rabbitmq_server_relations.py 2015-04-13 17:16:27 +0000
@@ -37,7 +37,7 @@
37 @patch('rabbitmq_server_relations.relation_set')37 @patch('rabbitmq_server_relations.relation_set')
38 @patch('apt_pkg.Cache')38 @patch('apt_pkg.Cache')
39 @patch('rabbitmq_server_relations.is_clustered')39 @patch('rabbitmq_server_relations.is_clustered')
40 @patch('rabbitmq_server_relations.configure_client_ssl')40 @patch('rabbitmq_server_relations.ssl_utils.configure_client_ssl')
41 @patch('rabbitmq_server_relations.unit_get')41 @patch('rabbitmq_server_relations.unit_get')
42 @patch('rabbitmq_server_relations.relation_get')42 @patch('rabbitmq_server_relations.relation_get')
43 @patch('rabbitmq_server_relations.is_elected_leader')43 @patch('rabbitmq_server_relations.is_elected_leader')
@@ -87,7 +87,7 @@
87 @patch('rabbitmq_server_relations.relation_set')87 @patch('rabbitmq_server_relations.relation_set')
88 @patch('apt_pkg.Cache')88 @patch('apt_pkg.Cache')
89 @patch('rabbitmq_server_relations.is_clustered')89 @patch('rabbitmq_server_relations.is_clustered')
90 @patch('rabbitmq_server_relations.configure_client_ssl')90 @patch('rabbitmq_server_relations.ssl_utils.configure_client_ssl')
91 @patch('rabbitmq_server_relations.unit_get')91 @patch('rabbitmq_server_relations.unit_get')
92 @patch('rabbitmq_server_relations.relation_get')92 @patch('rabbitmq_server_relations.relation_get')
93 @patch('rabbitmq_server_relations.is_elected_leader')93 @patch('rabbitmq_server_relations.is_elected_leader')

Subscribers

People subscribed via source and target branches