Add support for ceph-mon bootstrap
Add new relation to support bootstrapping a new deployment of the ceph-mon charm from an existing ceph charm deployment, supporting migration away from the deprecated ceph charm. Each member of the existing ceph application will present the required fsid and monitor-secret values, as well as its public address so that the related ceph-mon units can correctly seed from the exisitng MON cluster. Provide stop hook implementation, which will leaves OSD services running but will remove the ceph.conf provided directly from this charm, falling back to ceph.conf provided by other charms installed on the same machine. MON and MGR services will be shutdown and disabled. Closes-Bug: 1665159 Change-Id: I9bd1d7630a8eff53c65cb0f07d17e095fc7f32a9 Depends-On: Iac34d1bee4b51b55dfb3d14d315aae8526a0893c
This commit is contained in:
parent
f936367cac
commit
71390fe0cf
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,9 +2,11 @@ bin
|
||||
.idea
|
||||
.coverage
|
||||
.testrepository
|
||||
.stestr
|
||||
.tox
|
||||
*.sw[nop]
|
||||
.idea
|
||||
*.pyc
|
||||
.unit-state.db
|
||||
func-results.json
|
||||
.pydevproject
|
||||
|
12
README.md
12
README.md
@ -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
|
||||
|
1
hooks/bootstrap-source-relation-broken
Symbolic link
1
hooks/bootstrap-source-relation-broken
Symbolic link
@ -0,0 +1 @@
|
||||
ceph_hooks.py
|
1
hooks/bootstrap-source-relation-changed
Symbolic link
1
hooks/bootstrap-source-relation-changed
Symbolic link
@ -0,0 +1 @@
|
||||
ceph_hooks.py
|
1
hooks/bootstrap-source-relation-departed
Symbolic link
1
hooks/bootstrap-source-relation-departed
Symbolic link
@ -0,0 +1 @@
|
||||
ceph_hooks.py
|
1
hooks/bootstrap-source-relation-joined
Symbolic link
1
hooks/bootstrap-source-relation-joined
Symbolic link
@ -0,0 +1 @@
|
||||
ceph_hooks.py
|
@ -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,
|
||||
@ -235,10 +240,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)
|
||||
@ -553,6 +562,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():
|
||||
@ -653,6 +675,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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -29,6 +29,8 @@ provides:
|
||||
interface: ceph-osd
|
||||
radosgw:
|
||||
interface: ceph-radosgw
|
||||
bootstrap-source:
|
||||
interface: ceph-bootstrap
|
||||
storage:
|
||||
osd-devices:
|
||||
type: block
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user