Merge "Add support for ceph-mon bootstrap"

This commit is contained in:
Zuul 2017-10-18 08:46:42 +00:00 committed by Gerrit Code Review
commit 8500fd6134
13 changed files with 136 additions and 8 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ bin
*.pyc
.unit-state.db
func-results.json
.pydevproject

View File

@ -1,11 +1,21 @@
# Overview
---
**NOTE**
This charm is deprecated and will not receive updates past February 2018.
Existing users should refer to [Appendix A](https://docs.openstack.org/charm-deployment-guide/latest/)
of the Charm Deployment Guide for details of how to migration existing
deployments to the preferred ceph-mon and ceph-osd charms.
---
Ceph is a distributed storage and network file system designed to provide
excellent performance, reliability, and scalability.
This charm deploys a Ceph cluster.
# Usage
The ceph charm has two pieces of mandatory configuration for which no defaults

View File

@ -0,0 +1 @@
ceph_hooks.py

View File

@ -0,0 +1 @@
ceph_hooks.py

View File

@ -0,0 +1 @@
ceph_hooks.py

View File

@ -0,0 +1 @@
ceph_hooks.py

View File

@ -17,6 +17,7 @@
import os
import sys
import socket
import subprocess
sys.path.append('lib')
import ceph.utils as ceph
@ -47,6 +48,7 @@ from charmhelpers.core.hookenv import (
)
from charmhelpers.core.host import (
service_restart,
service_pause,
umount,
mkdir,
write_file,
@ -62,7 +64,10 @@ from charmhelpers.fetch import (
get_upstream_version,
)
from charmhelpers.payload.execd import execd_preinstall
from charmhelpers.contrib.openstack.alternatives import install_alternative
from charmhelpers.contrib.openstack.alternatives import (
install_alternative,
remove_alternative,
)
from charmhelpers.contrib.network.ip import (
get_ipv6_addr,
format_ipv6_addr,
@ -221,10 +226,14 @@ def get_ceph_context():
return cephcontext
def ceph_conf_path():
return "/var/lib/charm/{}/ceph.conf".format(service_name())
def emit_cephconf():
# 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())
charm_ceph_conf = ceph_conf_path()
mkdir(os.path.dirname(charm_ceph_conf), owner=ceph.ceph_user(),
group=ceph.ceph_user())
render('ceph.conf', charm_ceph_conf, get_ceph_context(), perms=0o644)
@ -539,6 +548,19 @@ def client_relation_changed():
log('mon cluster not in quorum', level=DEBUG)
@hooks.hook('bootstrap-source-relation-joined')
def bootstrap_source_joined(relid=None):
"""Provide required information to bootstrap ceph-mon cluster"""
if ceph.is_quorum():
source = {
'fsid': config('fsid'),
'monitor-secret': config('monitor-secret'),
'ceph-public-address': get_public_addr(),
}
relation_set(relation_id=relid,
relation_settings=source)
@hooks.hook('upgrade-charm.real')
@harden()
def upgrade_charm():
@ -639,6 +661,28 @@ def update_status():
log('Updating status.')
@hooks.hook('stop')
def stop():
# NOTE(jamespage)
# Ensure monitor is removed from monmap prior to shutdown
# otherwise we end up with odd quorum loss issues during
# migration.
cmd = ['ceph', 'mon', 'rm', socket.gethostname()]
subprocess.check_call(cmd)
# NOTE(jamespage)
# Pause MON and MGR processes running on this unit, leaving
# any OSD processes running, supporting the migration to
# using the ceph-mon charm.
service_pause('ceph-mon')
if cmp_pkgrevno('ceph', '12.0.0') >= 0:
service_pause('ceph-mgr@{}'.format(socket.gethostname()))
# NOTE(jamespage)
# Remove the ceph.conf provided by this charm so
# that the ceph.conf from other deployed applications
# can take priority post removal.
remove_alternative('ceph.conf', ceph_conf_path())
if __name__ == '__main__':
try:
hooks.execute(sys.argv)

View File

@ -70,12 +70,12 @@ class DisabledModuleAudit(BaseAudit):
"""Returns the modules which are enabled in Apache."""
output = subprocess.check_output(['apache2ctl', '-M'])
modules = []
for line in output.strip().split():
for line in output.splitlines():
# Each line of the enabled module output looks like:
# module_name (static|shared)
# Plus a header line at the top of the output which is stripped
# out by the regex.
matcher = re.search(r'^ (\S*)', line)
matcher = re.search(r'^ (\S*)_module (\S*)', line)
if matcher:
modules.append(matcher.group(1))
return modules

View File

@ -29,3 +29,16 @@ def install_alternative(name, target, source, priority=50):
target, name, source, str(priority)
]
subprocess.check_call(cmd)
def remove_alternative(name, source):
"""Remove an installed alternative configuration file
:param name: string name of the alternative to remove
:param source: string full path to alternative to remove
"""
cmd = [
'update-alternatives', '--remove',
name, source
]
subprocess.check_call(cmd)

View File

@ -218,6 +218,8 @@ def principal_unit():
for rid in relation_ids(reltype):
for unit in related_units(rid):
md = _metadata_unit(unit)
if not md:
continue
subordinate = md.pop('subordinate', None)
if not subordinate:
return unit
@ -511,7 +513,10 @@ def _metadata_unit(unit):
"""
basedir = os.sep.join(charm_dir().split(os.sep)[:-2])
unitdir = 'unit-{}'.format(unit.replace(os.sep, '-'))
with open(os.path.join(basedir, unitdir, 'charm', 'metadata.yaml')) as md:
joineddir = os.path.join(basedir, unitdir, 'charm', 'metadata.yaml')
if not os.path.exists(joineddir):
return None
with open(joineddir) as md:
return yaml.safe_load(md)

View File

@ -30,6 +30,8 @@ provides:
interface: ceph-osd
radosgw:
interface: ceph-radosgw
bootstrap-source:
interface: ceph-bootstrap
storage:
osd-devices:
type: block

View File

@ -218,6 +218,8 @@ def principal_unit():
for rid in relation_ids(reltype):
for unit in related_units(rid):
md = _metadata_unit(unit)
if not md:
continue
subordinate = md.pop('subordinate', None)
if not subordinate:
return unit
@ -511,7 +513,10 @@ def _metadata_unit(unit):
"""
basedir = os.sep.join(charm_dir().split(os.sep)[:-2])
unitdir = 'unit-{}'.format(unit.replace(os.sep, '-'))
with open(os.path.join(basedir, unitdir, 'charm', 'metadata.yaml')) as md:
joineddir = os.path.join(basedir, unitdir, 'charm', 'metadata.yaml')
if not os.path.exists(joineddir):
return None
with open(joineddir) as md:
return yaml.safe_load(md)

View File

@ -15,7 +15,7 @@
import copy
import unittest
from mock import patch, DEFAULT
from mock import patch, DEFAULT, call
import charmhelpers.contrib.storage.linux.ceph as ceph
import ceph_hooks
@ -287,3 +287,47 @@ class CephHooksTestCase(unittest.TestCase):
ceph_hooks.upgrade_charm()
mocks["apt_install"].assert_called_with(
["python-dbus", "lockfile-progs"])
class StopHookTestCase(unittest.TestCase):
@patch.object(ceph_hooks, 'ceph_conf_path')
@patch.object(ceph_hooks, 'socket')
@patch.object(ceph_hooks, 'subprocess')
@patch.object(ceph_hooks, 'service_pause')
@patch.object(ceph_hooks, 'cmp_pkgrevno')
@patch.object(ceph_hooks, 'remove_alternative')
def _test_stop(self,
remove_alternative,
cmp_pkgrevno,
service_pause,
subprocess,
socket,
ceph_conf_path,
ceph_mgr=False):
if ceph_mgr:
cmp_pkgrevno.return_value = 1
else:
cmp_pkgrevno.return_value = -1
socket.gethostname.return_value = 'myself'
ceph_conf_path.return_value = '/var/lib/charm/me/ceph.conf'
ceph_hooks.stop()
subprocess.check_call.assert_called_with(
['ceph', 'mon', 'rm', 'myself']
)
if ceph_mgr:
service_pause.assert_has_calls([
call('ceph-mon'),
call('ceph-mgr@myself')
])
else:
service_pause.assert_called_once_with('ceph-mon')
remove_alternative.assert_called_with('ceph.conf',
'/var/lib/charm/me/ceph.conf')
def test_stop_jewel(self):
self._test_stop()
def test_stop_luminous(self):
self._test_stop(ceph_mgr=True)