charm-ceph-radosgw/hooks/ceph_radosgw_context.py
James Page 5d2dfd94dd Drop apache+mod-fastcgi support
The ceph project has focussed on running the RADOS Gateway using
the embedded civetweb engine for many cycles now; mod-fastcgi is
buggy and no longer provided in Ubuntu as of 17.04, so switch to
always running in embedded mode.

Existing installs will be upgraded to run in this mode, purging
apache related packaging and configuration.

Change-Id: I90e6c047d78de2b0ebf8c24bd2f2d6d1bfbd5c5d
Closes-Bug: 1657370
2017-01-18 17:30:33 +00:00

194 lines
6.1 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.
import os
import re
import socket
import tempfile
import shutil
from charmhelpers.contrib.openstack import context
from charmhelpers.contrib.hahelpers.cluster import (
determine_api_port,
determine_apache_port,
)
from charmhelpers.core.host import cmp_pkgrevno
from charmhelpers.core.hookenv import (
DEBUG,
WARNING,
config,
log,
relation_ids,
related_units,
relation_get,
)
from charmhelpers.contrib.network.ip import (
format_ipv6_addr,
get_host_ip,
get_ipv6_addr,
)
from charmhelpers.contrib.storage.linux.ceph import CephConfContext
class HAProxyContext(context.HAProxyContext):
def __call__(self):
ctxt = super(HAProxyContext, self).__call__()
port = config('port')
# Apache ports
a_cephradosgw_api = determine_apache_port(port, singlenode_mode=True)
port_mapping = {
'cephradosgw-server': [port, a_cephradosgw_api]
}
ctxt['cephradosgw_bind_port'] = determine_api_port(
port,
singlenode_mode=True,
)
# for haproxy.conf
ctxt['service_ports'] = port_mapping
return ctxt
class IdentityServiceContext(context.IdentityServiceContext):
interfaces = ['identity-service']
def __call__(self):
ctxt = super(IdentityServiceContext, self).__call__()
if not ctxt:
return
ctxt['admin_token'] = None
for relid in relation_ids('identity-service'):
for unit in related_units(relid):
if not ctxt.get('admin_token'):
ctxt['admin_token'] = \
relation_get('admin_token', unit, relid)
ctxt['auth_type'] = 'keystone'
ctxt['user_roles'] = config('operator-roles')
ctxt['cache_size'] = config('cache-size')
ctxt['revocation_check_interval'] = config('revocation-check-interval')
if self.context_complete(ctxt):
return ctxt
return {}
def ensure_host_resolvable_v6(hostname):
"""Ensure that we can resolve our hostname to an IPv6 address by adding it
to /etc/hosts if it is not already resolvable.
"""
try:
socket.getaddrinfo(hostname, None, socket.AF_INET6)
except socket.gaierror:
log("Host '%s' is not ipv6 resolvable - adding to /etc/hosts" %
hostname, level=DEBUG)
else:
log("Host '%s' appears to be ipv6 resolvable" % (hostname),
level=DEBUG)
return
# This must be the backend address used by haproxy
host_addr = get_ipv6_addr(exc_list=[config('vip')])[0]
dtmp = tempfile.mkdtemp()
try:
tmp_hosts = os.path.join(dtmp, 'hosts')
shutil.copy('/etc/hosts', tmp_hosts)
with open(tmp_hosts, 'a+') as fd:
lines = fd.readlines()
for line in lines:
key = "^%s\s+" % (host_addr)
if re.search(key, line):
break
else:
fd.write("%s\t%s\n" % (host_addr, hostname))
os.rename(tmp_hosts, '/etc/hosts')
finally:
shutil.rmtree(dtmp)
class MonContext(context.OSContextGenerator):
interfaces = ['ceph-radosgw']
def __call__(self):
if not relation_ids('mon'):
return {}
mon_hosts = []
auths = []
for relid in relation_ids('mon'):
for unit in related_units(relid):
ceph_public_addr = relation_get('ceph-public-address', unit,
relid)
if ceph_public_addr:
host_ip = format_ipv6_addr(ceph_public_addr) or \
get_host_ip(ceph_public_addr)
mon_hosts.append('{}:6789'.format(host_ip))
_auth = relation_get('auth', unit, relid)
if _auth:
auths.append(_auth)
if len(set(auths)) != 1:
e = ("Inconsistent or absent auth returned by mon units. Setting "
"auth_supported to 'none'")
log(e, level=WARNING)
auth = 'none'
else:
auth = auths[0]
# /etc/init.d/radosgw mandates that a dns name is used for this
# parameter so ensure that address is resolvable
host = socket.gethostname()
if config('prefer-ipv6'):
ensure_host_resolvable_v6(host)
port = determine_apache_port(config('port'), singlenode_mode=True)
if config('prefer-ipv6'):
port = "[::]:%s" % (port)
mon_hosts.sort()
ctxt = {
'auth_supported': auth,
'mon_hosts': ' '.join(mon_hosts),
'hostname': host,
'old_auth': cmp_pkgrevno('radosgw', "0.51") < 0,
'use_syslog': str(config('use-syslog')).lower(),
'loglevel': config('loglevel'),
'port': port,
'ipv6': config('prefer-ipv6')
}
certs_path = '/var/lib/ceph/nss'
paths = [os.path.join(certs_path, 'ca.pem'),
os.path.join(certs_path, 'signing_certificate.pem')]
if all([os.path.isfile(p) for p in paths]):
ctxt['cms'] = True
# NOTE(dosaboy): these sections must correspond to what is supported in
# the config template.
sections = ['global', 'client.radosgw.gateway']
user_provided = CephConfContext(permitted_sections=sections)()
user_provided = {k.replace('.', '_'): user_provided[k]
for k in user_provided}
ctxt.update(user_provided)
if self.context_complete(ctxt):
return ctxt
return {}