Extend check_rabbitmq.py to honor ssl=only
This patch enables checks of rabbitmq when SSL is enabled, when ssl config option is set to 'on' both ports (5672 and 5671) will be checked. Change-Id: Ia0bab1dca65112cd06ae382f6ebc1cc280d7b130 Closes-Bug: 1687916
This commit is contained in:
parent
a649fb15de
commit
6ede4d38b3
@ -48,9 +48,9 @@ except ImportError:
|
||||
import psutil
|
||||
|
||||
|
||||
ssl_key_file = "/etc/rabbitmq/rabbit-server-privkey.pem"
|
||||
ssl_cert_file = "/etc/rabbitmq/rabbit-server-cert.pem"
|
||||
ssl_ca_file = "/etc/rabbitmq/rabbit-server-ca.pem"
|
||||
SSL_KEY_FILE = "/etc/rabbitmq/rabbit-server-privkey.pem"
|
||||
SSL_CERT_FILE = "/etc/rabbitmq/rabbit-server-cert.pem"
|
||||
SSL_CA_FILE = "/etc/rabbitmq/rabbit-server-ca.pem"
|
||||
RABBITMQ_CTL = '/usr/sbin/rabbitmqctl'
|
||||
ENV_CONF = '/etc/rabbitmq/rabbitmq-env.conf'
|
||||
|
||||
@ -90,9 +90,9 @@ class RabbitMQSSLContext(object):
|
||||
gid = grp.getgrnam("rabbitmq").gr_gid
|
||||
|
||||
for contents, path in (
|
||||
(ssl_key, ssl_key_file),
|
||||
(ssl_cert, ssl_cert_file),
|
||||
(ssl_ca, ssl_ca_file)):
|
||||
(ssl_key, SSL_KEY_FILE),
|
||||
(ssl_cert, SSL_CERT_FILE),
|
||||
(ssl_ca, SSL_CA_FILE)):
|
||||
|
||||
if not contents:
|
||||
continue
|
||||
@ -100,20 +100,26 @@ class RabbitMQSSLContext(object):
|
||||
with open(path, 'w') as fh:
|
||||
fh.write(contents)
|
||||
|
||||
if path == SSL_CA_FILE:
|
||||
# the CA can be world readable and it will allow clients to
|
||||
# verify the certificate offered by rabbit.
|
||||
os.chmod(path, 0o644)
|
||||
else:
|
||||
os.chmod(path, 0o640)
|
||||
|
||||
os.chown(path, uid, gid)
|
||||
|
||||
data = {
|
||||
"ssl_port": ssl_port,
|
||||
"ssl_cert_file": ssl_cert_file,
|
||||
"ssl_key_file": ssl_key_file,
|
||||
"ssl_cert_file": SSL_CERT_FILE,
|
||||
"ssl_key_file": SSL_KEY_FILE,
|
||||
"ssl_client": ssl_client,
|
||||
"ssl_ca_file": "",
|
||||
"ssl_only": ssl_only
|
||||
}
|
||||
|
||||
if ssl_ca:
|
||||
data["ssl_ca_file"] = ssl_ca_file
|
||||
data["ssl_ca_file"] = SSL_CA_FILE
|
||||
|
||||
return data
|
||||
|
||||
|
@ -31,6 +31,7 @@ except ImportError:
|
||||
|
||||
import rabbit_utils as rabbit
|
||||
import ssl_utils
|
||||
from rabbitmq_context import SSL_CA_FILE
|
||||
|
||||
from lib.utils import (
|
||||
chown, chmod,
|
||||
@ -616,12 +617,33 @@ def update_nrpe_checks():
|
||||
rabbit.grant_permissions(user, vhost)
|
||||
|
||||
nrpe_compat = nrpe.NRPE(hostname=hostname)
|
||||
if config('ssl') in ['off', 'on']:
|
||||
cmd = ('{plugins_dir}/check_rabbitmq.py --user {user} '
|
||||
'--password {password} --vhost {vhost}')
|
||||
cmd = cmd.format(plugins_dir=NAGIOS_PLUGINS, user=user,
|
||||
password=password, vhost=vhost)
|
||||
nrpe_compat.add_check(
|
||||
shortname=rabbit.RABBIT_USER,
|
||||
description='Check RabbitMQ {%s}' % myunit,
|
||||
check_cmd='{}/check_rabbitmq.py --user {} --password {} --vhost {}'
|
||||
''.format(NAGIOS_PLUGINS, user, password, vhost)
|
||||
check_cmd=cmd
|
||||
)
|
||||
if config('ssl') in ['only', 'on']:
|
||||
log('Adding rabbitmq SSL check', level=DEBUG)
|
||||
cmd = ('{plugins_dir}/check_rabbitmq.py --user {user} '
|
||||
'--password {password} --vhost {vhost} '
|
||||
'--ssl --ssl-ca {ssl_ca} --port {port}')
|
||||
cmd = cmd.format(plugins_dir=NAGIOS_PLUGINS,
|
||||
user=user,
|
||||
password=password,
|
||||
port=int(config('ssl_port')),
|
||||
vhost=vhost,
|
||||
ssl_ca=SSL_CA_FILE)
|
||||
nrpe_compat.add_check(
|
||||
shortname=rabbit.RABBIT_USER + "_ssl",
|
||||
description='Check RabbitMQ (SSL) {%s}' % myunit,
|
||||
check_cmd=cmd
|
||||
)
|
||||
|
||||
if config('queue_thresholds'):
|
||||
cmd = ""
|
||||
# If value of queue_thresholds is incorrect we want the hook to fail
|
||||
@ -695,7 +717,17 @@ def config_changed():
|
||||
if rabbit.archive_upgrade_available():
|
||||
rabbit.install_or_upgrade_packages()
|
||||
|
||||
if config('ssl') == 'off':
|
||||
open_port(5672)
|
||||
close_port(int(config('ssl_port')))
|
||||
elif config('ssl') == 'on':
|
||||
open_port(5672)
|
||||
open_port(int(config('ssl_port')))
|
||||
elif config('ssl') == 'only':
|
||||
close_port(5672)
|
||||
open_port(int(config('ssl_port')))
|
||||
else:
|
||||
log("Unknown ssl config value: '%s'" % config('ssl'), level=ERROR)
|
||||
|
||||
chown(RABBIT_DIR, rabbit.RABBIT_USER, rabbit.RABBIT_USER)
|
||||
chmod(RABBIT_DIR, 0o775)
|
||||
|
@ -38,14 +38,18 @@ def alarm_handler(signum, frame):
|
||||
os._exit(1)
|
||||
|
||||
|
||||
def get_connection(host_port, user, password, vhost):
|
||||
def get_connection(host_port, user, password, vhost, ssl, ssl_ca):
|
||||
""" connect to the amqp service """
|
||||
if options.verbose:
|
||||
print "Connection to %s requested" % host_port
|
||||
try:
|
||||
ret = amqp.Connection(host=host_port, userid=user,
|
||||
password=password, virtual_host=vhost,
|
||||
insist=False)
|
||||
params = {'host': host_port, 'userid': user, 'password': password,
|
||||
'virtual_host': vhost, 'insist': False}
|
||||
if ssl:
|
||||
params['ssl'] = {'ca_certs': ssl_ca}
|
||||
|
||||
ret = amqp.Connection(**params)
|
||||
|
||||
except (socket.error, TypeError), e:
|
||||
print "ERROR: Could not connect to RabbitMQ server %s:%d" % (
|
||||
options.host, options.port)
|
||||
@ -53,9 +57,9 @@ def get_connection(host_port, user, password, vhost):
|
||||
print e
|
||||
raise
|
||||
sys.exit(2)
|
||||
except:
|
||||
print "ERROR: Unknown error connecting to RabbitMQ server %s:%d" % (
|
||||
options.host, options.port)
|
||||
except Exception as ex:
|
||||
print("ERROR: Unknown error connecting to RabbitMQ server %s:%d: %s"
|
||||
% (options.host, options.port, ex))
|
||||
if options.verbose:
|
||||
raise
|
||||
sys.exit(3)
|
||||
@ -174,12 +178,12 @@ def main_loop(conn, exname):
|
||||
return consumer.loop(timeout=options.timeout)
|
||||
|
||||
|
||||
def main(host, port, exname, extype, user, password, vhost):
|
||||
def main(host, port, exname, extype, user, password, vhost, ssl, ssl_ca):
|
||||
""" setup the connection and the communication channel """
|
||||
sys.stdout = os.fdopen(os.dup(1), "w", 0)
|
||||
host_port = "%s:%s" % (host, port)
|
||||
conn = get_connection(host_port, user, password, vhost)
|
||||
chan = conn.channel()
|
||||
conn = get_connection(host_port, user, password, vhost, ssl, ssl_ca)
|
||||
|
||||
if setup_exchange(conn, exname, extype):
|
||||
if options.verbose:
|
||||
print "Created %s exchange of type %s" % (exname, extype)
|
||||
@ -187,8 +191,13 @@ def main(host, port, exname, extype, user, password, vhost):
|
||||
if options.verbose:
|
||||
print "Reusing existing exchange %s of type %s" % (exname, extype)
|
||||
ret = main_loop(conn, exname)
|
||||
chan.close()
|
||||
|
||||
try:
|
||||
conn.close()
|
||||
except socket.error:
|
||||
# when using SSL socket.shutdown() fails inside amqplib.
|
||||
pass
|
||||
|
||||
return ret
|
||||
|
||||
if __name__ == '__main__':
|
||||
@ -222,6 +231,10 @@ if __name__ == '__main__':
|
||||
parser.add_option("--vhost", dest="vhost", default="/",
|
||||
help="RabbitMQ vhost [default=%default]",
|
||||
metavar="VHOST")
|
||||
parser.add_option("--ssl", dest="ssl", default=False, action="store_true",
|
||||
help="Connect using SSL")
|
||||
parser.add_option("--ssl-ca", metavar="FILE", dest="ssl_ca",
|
||||
help="SSL CA certificate path")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
if options.verbose:
|
||||
@ -229,7 +242,8 @@ if __name__ == '__main__':
|
||||
Using AMQP setup: host:port=%s:%d exchange_name=%s exchange_type=%s
|
||||
""" % (options.host, options.port, options.exchange, options.type)
|
||||
ret = main(options.host, options.port, options.exchange, options.type,
|
||||
options.user, options.password, options.vhost)
|
||||
options.user, options.password, options.vhost, options.ssl,
|
||||
options.ssl_ca)
|
||||
if ret:
|
||||
print "Ok: sent and received %d test messages" % options.messages
|
||||
sys.exit(0)
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
@ -34,6 +35,7 @@ with patch('charmhelpers.contrib.hardening.harden.harden') as mock_dec:
|
||||
mock_dec.side_effect = (lambda *dargs, **dkwargs: lambda f:
|
||||
lambda *args, **kwargs: f(*args, **kwargs))
|
||||
import rabbitmq_server_relations
|
||||
import rabbit_utils
|
||||
|
||||
TO_PATCH = [
|
||||
# charmhelpers.core.hookenv
|
||||
@ -48,6 +50,11 @@ class RelationUtil(CharmTestCase):
|
||||
self.fake_repo = {}
|
||||
super(RelationUtil, self).setUp(rabbitmq_server_relations,
|
||||
TO_PATCH)
|
||||
self.tmp_dir = tempfile.mkdtemp()
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tmp_dir)
|
||||
super(RelationUtil, self).tearDown()
|
||||
|
||||
@patch('rabbitmq_server_relations.rabbit.leader_node_is_ready')
|
||||
@patch('rabbitmq_server_relations.peer_store_and_set')
|
||||
@ -278,3 +285,71 @@ class RelationUtil(CharmTestCase):
|
||||
finally:
|
||||
if os.path.exists(tmpdir):
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
@patch('rabbitmq_server_relations.local_unit')
|
||||
@patch('charmhelpers.contrib.charmsupport.nrpe.NRPE.add_check')
|
||||
@patch('subprocess.check_call')
|
||||
@patch('rabbit_utils.get_rabbit_password_on_disk')
|
||||
@patch('charmhelpers.contrib.charmsupport.nrpe.relation_ids')
|
||||
@patch('charmhelpers.contrib.charmsupport.nrpe.config')
|
||||
@patch('charmhelpers.contrib.charmsupport.nrpe.get_nagios_unit_name')
|
||||
@patch('charmhelpers.contrib.charmsupport.nrpe.get_nagios_hostname')
|
||||
@patch('os.fchown')
|
||||
@patch('rabbitmq_server_relations.charm_dir')
|
||||
@patch('subprocess.check_output')
|
||||
@patch('rabbitmq_server_relations.config')
|
||||
def test_update_nrpe_checks(self, mock_config, mock_check_output,
|
||||
mock_charm_dir, mock_fchown,
|
||||
mock_get_nagios_hostname,
|
||||
mock_get_nagios_unit_name, mock_config2,
|
||||
mock_nrpe_relation_ids,
|
||||
mock_get_rabbit_password_on_disk,
|
||||
mock_check_call, mock_add_check,
|
||||
mock_local_unit):
|
||||
|
||||
self.test_config.set('ssl', 'on')
|
||||
|
||||
mock_charm_dir.side_effect = lambda: self.tmp_dir
|
||||
mock_config.side_effect = self.test_config
|
||||
mock_config2.side_effect = self.test_config
|
||||
rabbitmq_server_relations.STATS_CRONFILE = os.path.join(
|
||||
self.tmp_dir, "rabbitmq-stats")
|
||||
mock_get_nagios_hostname.return_value = "foo-0"
|
||||
mock_get_nagios_unit_name.return_value = "bar-0"
|
||||
mock_get_rabbit_password_on_disk.return_value = "qwerty"
|
||||
mock_nrpe_relation_ids.side_effect = lambda x: [
|
||||
'nrpe-external-master:1']
|
||||
mock_local_unit.return_value = 'unit/0'
|
||||
|
||||
rabbitmq_server_relations.update_nrpe_checks()
|
||||
|
||||
mock_check_output.assert_any_call(
|
||||
['/usr/bin/rsync', '-r', '--delete', '--executability',
|
||||
'%s/scripts/collect_rabbitmq_stats.sh' % self.tmp_dir,
|
||||
'/usr/local/bin/collect_rabbitmq_stats.sh'],
|
||||
stderr=subprocess.STDOUT)
|
||||
|
||||
# regular check on 5672
|
||||
cmd = ('{plugins_dir}/check_rabbitmq.py --user {user} '
|
||||
'--password {password} --vhost {vhost}').format(
|
||||
plugins_dir=rabbitmq_server_relations.NAGIOS_PLUGINS,
|
||||
user='nagios-unit-0', vhost='nagios-unit-0',
|
||||
password='qwerty')
|
||||
|
||||
mock_add_check.assert_any_call(
|
||||
shortname=rabbit_utils.RABBIT_USER,
|
||||
description='Check RabbitMQ {%s}' % 'bar-0', check_cmd=cmd)
|
||||
|
||||
# check on ssl port 5671
|
||||
cmd = ('{plugins_dir}/check_rabbitmq.py --user {user} '
|
||||
'--password {password} --vhost {vhost} '
|
||||
'--ssl --ssl-ca {ssl_ca} --port {port}').format(
|
||||
plugins_dir=rabbitmq_server_relations.NAGIOS_PLUGINS,
|
||||
user='nagios-unit-0',
|
||||
password='qwerty',
|
||||
port=int(self.test_config['ssl_port']),
|
||||
vhost='nagios-unit-0',
|
||||
ssl_ca=rabbitmq_server_relations.SSL_CA_FILE)
|
||||
mock_add_check.assert_any_call(
|
||||
shortname=rabbit_utils.RABBIT_USER + "_ssl",
|
||||
description='Check RabbitMQ (SSL) {%s}' % 'bar-0', check_cmd=cmd)
|
||||
|
@ -117,6 +117,15 @@ class TestConfig(object):
|
||||
def __getitem__(self, key):
|
||||
return self.get(key)
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.config
|
||||
|
||||
def __call__(self, key=None):
|
||||
if key:
|
||||
return self.get(key)
|
||||
else:
|
||||
return self
|
||||
|
||||
|
||||
class TestRelation(object):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user