charm-rabbitmq-server/hooks/rabbitmq_context.py
James Page ef1997c092 Re-license charm as Apache-2.0
All contributions to this charm where made under Canonical
copyright; switch to Apache-2.0 license as agreed so we
can move forward with official project status.

Change-Id: Ie4fc5353520eb3c3c0d14b1aa35703aeaea6ac40
2016-07-01 18:06:36 +01:00

142 lines
3.9 KiB
Python

# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from charmhelpers.contrib.ssl.service import ServiceCA
from charmhelpers.core.hookenv import (
open_port,
close_port,
config,
log,
ERROR,
)
import sys
import pwd
import grp
import os
import base64
import ssl_utils
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'
def convert_from_base64(v):
# Rabbit originally supported pem encoded key/cert in config, play
# nice on upgrades as we now expect base64 encoded key/cert/ca.
if not v:
return v
if v.startswith('-----BEGIN'):
return v
try:
return base64.b64decode(v)
except TypeError:
return v
class RabbitMQSSLContext(object):
def enable_ssl(self, ssl_key, ssl_cert, ssl_port,
ssl_ca=None, ssl_only=False, ssl_client=None):
if not os.path.exists(RABBITMQ_CTL):
log('Deferring SSL configuration, RabbitMQ not yet installed')
return {}
uid = pwd.getpwnam("root").pw_uid
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)):
if not contents:
continue
with open(path, 'w') as fh:
fh.write(contents)
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_client": ssl_client,
"ssl_ca_file": "",
"ssl_only": ssl_only
}
if ssl_ca:
data["ssl_ca_file"] = ssl_ca_file
return data
def __call__(self):
"""
The legacy config support adds some additional complications.
ssl_enabled = True, ssl = off -> ssl enabled
ssl_enabled = False, ssl = on -> ssl enabled
"""
ssl_mode, external_ca = ssl_utils.get_ssl_mode()
ctxt = {
'ssl_mode': ssl_mode,
}
if ssl_mode == 'off':
close_port(config('ssl_port'))
ssl_utils.reconfigure_client_ssl()
return ctxt
ssl_key = convert_from_base64(config('ssl_key'))
ssl_cert = convert_from_base64(config('ssl_cert'))
ssl_ca = convert_from_base64(config('ssl_ca'))
ssl_port = config('ssl_port')
# If external managed certs then we need all the fields.
if (ssl_mode in ('on', 'only') and any((ssl_key, ssl_cert)) and
not all((ssl_key, ssl_cert))):
log('If ssl_key or ssl_cert are specified both are required.',
level=ERROR)
sys.exit(1)
if not external_ca:
ssl_cert, ssl_key, ssl_ca = ServiceCA.get_service_cert()
ctxt.update(self.enable_ssl(
ssl_key, ssl_cert, ssl_port, ssl_ca,
ssl_only=(ssl_mode == "only"), ssl_client=False
))
ssl_utils.reconfigure_client_ssl(True)
open_port(ssl_port)
return ctxt
class RabbitMQClusterContext(object):
def __call__(self):
return {
'cluster_partition_handling': config('cluster-partition-handling'),
}