charm-ceph-proxy/hooks/ceph_hooks.py

276 lines
8.1 KiB
Python
Executable File

#!/usr/bin/python
#
# Copyright 2012 Canonical Ltd.
#
# Authors:
# Paul Collins <paul.collins@canonical.com>
# James Page <james.page@ubuntu.com>
#
import glob
import os
import random
import shutil
import socket
import subprocess
import sys
import uuid
import time
import ceph
from charmhelpers.core import host
from charmhelpers.core import hookenv
from charmhelpers.core.hookenv import (
log,
DEBUG,
config,
relation_ids,
related_units,
relation_get,
relation_set,
leader_set, leader_get,
is_leader,
remote_unit,
Hooks, UnregisteredHookError,
service_name,
relations_of_type,
status_set,
local_unit)
from charmhelpers.core.host import (
service_restart,
mkdir,
write_file,
rsync,
cmp_pkgrevno,
service_stop, service_start)
from charmhelpers.fetch import (
apt_install,
apt_update,
filter_installed_packages,
add_source
)
from charmhelpers.payload.execd import execd_preinstall
from charmhelpers.contrib.openstack.alternatives import install_alternative
from charmhelpers.contrib.network.ip import (
get_ipv6_addr,
format_ipv6_addr,
)
from charmhelpers.core.sysctl import create as create_sysctl
from charmhelpers.core.templating import render
from charmhelpers.contrib.storage.linux.ceph import (
monitor_key_set,
monitor_key_exists,
monitor_key_get,
get_mon_map)
from ceph_broker import (
process_requests
)
from utils import (
get_public_addr,
get_unit_hostname,
)
from charmhelpers.contrib.charmsupport import nrpe
from charmhelpers.contrib.hardening.harden import harden
hooks = Hooks()
def install_upstart_scripts():
# Only install upstart configurations for older versions
if cmp_pkgrevno('ceph', "0.55.1") < 0:
for x in glob.glob('files/upstart/*.conf'):
shutil.copy(x, '/etc/init/')
@hooks.hook('install.real')
@harden()
def install():
execd_preinstall()
add_source(config('source'), config('key'))
apt_update(fatal=True)
apt_install(packages=ceph.PACKAGES, fatal=True)
install_upstart_scripts()
def emit_cephconf():
cephcontext = {
'mon_hosts': config('monitor-hosts'),
'fsid': config('fsid'),
'use_syslog': str(config('use-syslog')).lower(),
'loglevel': config('loglevel'),
}
# Install ceph.conf as an alternative to support
# co-existence with other charms that write this file
charm_ceph_conf = "/var/lib/charm/{}/ceph.conf".format(service_name())
mkdir(os.path.dirname(charm_ceph_conf), owner=ceph.ceph_user(),
group=ceph.ceph_user())
render('ceph.conf', charm_ceph_conf, cephcontext, perms=0o644)
install_alternative('ceph.conf', '/etc/ceph/ceph.conf',
charm_ceph_conf, 100)
keyring = 'ceph.client.admin.keyring'
keyring_path = '/etc/ceph/' + keyring
render(keyring, keyring_path, {'admin_key': config('admin-key')}, owner=ceph.ceph_user(), perms=0o600)
keyring = 'keyring'
keyring_path = '/var/lib/ceph/mon/ceph-' + get_unit_hostname()+ '/' + keyring
render('mon.keyring', keyring_path, {'admin_key': config('admin-key')}, owner=ceph.ceph_user(), perms=0o600)
notify_radosgws()
notify_client()
@hooks.hook('config-changed')
@harden()
def config_changed():
emit_cephconf()
def notify_radosgws():
for relid in relation_ids('radosgw'):
for unit in related_units(relid):
radosgw_relation(relid=relid, unit=unit)
def notify_client():
for relid in relation_ids('client'):
client_relation_joined(relid)
@hooks.hook('radosgw-relation-changed')
@hooks.hook('radosgw-relation-joined')
def radosgw_relation(relid=None, unit=None):
# Install radosgw for admin tools
apt_install(packages=filter_installed_packages(['radosgw']))
if not unit:
unit = remote_unit()
# NOTE: radosgw needs some usage OSD storage, so defer key
# provision until OSD units are detected.
if ready():
log('mon cluster in quorum and osds related '
'- providing radosgw with keys')
public_addr = get_public_addr()
data = {
'fsid': config('fsid'),
'radosgw_key': ceph.get_radosgw_key(),
'auth': 'cephx',
'ceph-public-address': public_addr,
}
settings = relation_get(rid=relid, unit=unit)
"""Process broker request(s)."""
if 'broker_req' in settings:
if ceph.is_leader():
rsp = process_requests(settings['broker_req'])
unit_id = unit.replace('/', '-')
unit_response_key = 'broker-rsp-' + unit_id
data[unit_response_key] = rsp
else:
log("Not leader - ignoring broker request", level=DEBUG)
relation_set(relation_id=relid, relation_settings=data)
else:
log('FSID or admin key not provided, please configure them')
@hooks.hook('client-relation-joined')
def client_relation_joined(relid=None):
if ready():
service_name = None
if relid is None:
units = [remote_unit()]
service_name = units[0].split('/')[0]
else:
units = related_units(relid)
if len(units) > 0:
service_name = units[0].split('/')[0]
if service_name is not None:
public_addr = get_public_addr()
data = {'key': ceph.get_named_key(service_name),
'auth': 'cephx',
'ceph-public-address': public_addr}
relation_set(relation_id=relid,
relation_settings=data)
else:
log('FSID or admin key not provided, please configure them')
@hooks.hook('client-relation-changed')
def client_relation_changed():
"""Process broker requests from ceph client relations."""
if ready():
settings = relation_get()
if 'broker_req' in settings:
if not ceph.is_leader():
log("Not leader - ignoring broker request", level=DEBUG)
else:
rsp = process_requests(settings['broker_req'])
unit_id = remote_unit().replace('/', '-')
unit_response_key = 'broker-rsp-' + unit_id
# broker_rsp is being left for backward compatibility,
# unit_response_key superscedes it
data = {
'broker_rsp': rsp,
unit_response_key: rsp,
}
relation_set(relation_settings=data)
else:
log('FSID or admin key not provided, please configure them')
def ready():
return config('fsid') and config('admin-key')
def assess_status():
'''Assess status of current unit'''
if ready():
status_set('active', 'Ready to proxy settings')
else:
status_set('blocked', 'Ensure FSID and admin-key are set')
# moncount = int(config('monitor-count'))
# units = get_peer_units()
# # not enough peers and mon_count > 1
# if len(units.keys()) < moncount:
# status_set('blocked', 'Insufficient peer units to bootstrap'
# ' cluster (require {})'.format(moncount))
# return
# # mon_count > 1, peers, but no ceph-public-address
# ready = sum(1 for unit_ready in units.itervalues() if unit_ready)
# if ready < moncount:
# status_set('waiting', 'Peer units detected, waiting for addresses')
# return
# # active - bootstrapped + quorum status check
# if ceph.is_bootstrapped() and ceph.is_quorum():
# status_set('active', 'Unit is ready and clustered')
# else:
# # Unit should be running and clustered, but no quorum
# # TODO: should this be blocked or waiting?
# status_set('blocked', 'Unit not clustered (no quorum)')
# # If there's a pending lock for this unit,
# # can i get the lock?
# # reboot the ceph-mon process
# status_set('active', 'doing some shit maybe?')
@hooks.hook('update-status')
@harden()
def update_status():
log('Updating status.')
if __name__ == '__main__':
try:
hooks.execute(sys.argv)
except UnregisteredHookError as e:
log('Unknown hook {} - skipping.'.format(e))
assess_status()