charm-cinder-ceph/hooks/cinder_contexts.py

162 lines
5.5 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.core.hookenv import (
config,
service_name,
is_relation_made,
leader_get,
log,
relation_get,
relation_ids,
related_units,
DEBUG,
)
from charmhelpers.contrib.openstack.context import (
CephContext,
OSContextGenerator,
)
from charmhelpers.contrib.openstack.utils import (
get_os_codename_package,
CompareOpenStackReleases,
)
from charmhelpers.contrib.network.ip import (
format_ipv6_addr,
)
CHARM_CEPH_CONF = '/var/lib/charm/{}/ceph.conf'
def ceph_config_file():
return CHARM_CEPH_CONF.format(service_name())
class CephAccessContext(OSContextGenerator):
interfaces = ['ceph-access']
def __call__(self):
"""Simple check to validate that compute units are present"""
for r_id in relation_ids(self.interfaces[0]):
if related_units(r_id):
return {'complete': True}
return {}
class CephSubordinateContext(OSContextGenerator):
interfaces = ['ceph-cinder']
def __call__(self):
"""
Used to generate template context to be added to cinder.conf in the
presence of a ceph relation.
"""
if not is_relation_made('ceph', 'key'):
return {}
service = service_name()
os_codename = get_os_codename_package('cinder-common')
if CompareOpenStackReleases(os_codename) >= "icehouse":
volume_driver = 'cinder.volume.drivers.rbd.RBDDriver'
else:
volume_driver = 'cinder.volume.driver.RBDDriver'
if config('volume-backend-name'):
volume_backend_name = config('volume-backend-name')
else:
volume_backend_name = service
if config('pool-type') == 'erasure-coded':
pool_name = (
config('ec-rbd-metadata-pool') or
"{}-metadata".format(config('rbd-pool-name') or
service)
)
else:
pool_name = config('rbd-pool-name') or service
section = {service: [('volume_backend_name', volume_backend_name),
('volume_driver', volume_driver),
('rbd_pool', pool_name),
('rbd_user', service),
('rbd_secret_uuid', leader_get('secret-uuid')),
('rbd_ceph_conf', ceph_config_file())]}
if CompareOpenStackReleases(os_codename) >= "mitaka":
section[service].append(('report_discard_supported', True))
if CompareOpenStackReleases(os_codename) >= "ocata":
section[service].append(('rbd_exclusive_cinder_pool', True))
if CompareOpenStackReleases(os_codename) >= "pike" \
and config('backend-availability-zone'):
section[service].append(
('backend_availability_zone',
config('backend-availability-zone')))
if CompareOpenStackReleases(os_codename) >= "queens":
section[service].append(
('rbd_flatten_volume_from_snapshot',
config('rbd-flatten-volume-from-snapshot')))
return {'cinder': {'/etc/cinder/cinder.conf': {'sections': section}}}
class CephReplicationDeviceContext(CephContext):
"""Generates context for /etc/ceph/ceph.conf templates."""
interfaces = ['ceph-replication-device']
def __call__(self):
if not relation_ids('ceph-replication-device'):
return {}
log('Generating template context for ceph-replication-device',
level=DEBUG)
mon_hosts = []
ctxt = {
'use_syslog': str(config('use-syslog')).lower()
}
for rid in relation_ids('ceph-replication-device'):
for unit in related_units(rid):
if not ctxt.get('auth'):
ctxt['auth'] = relation_get('auth', rid=rid, unit=unit)
if not ctxt.get('key'):
ctxt['key'] = relation_get('key', rid=rid, unit=unit)
ceph_addrs = relation_get('ceph-public-address', rid=rid,
unit=unit)
if ceph_addrs:
for addr in ceph_addrs.split(' '):
mon_hosts.append(format_ipv6_addr(addr) or addr)
else:
priv_addr = relation_get('private-address', rid=rid,
unit=unit)
mon_hosts.append(format_ipv6_addr(priv_addr) or priv_addr)
ctxt['mon_hosts'] = ' '.join(sorted(mon_hosts))
if not self.context_complete(ctxt):
return {}
return ctxt
class CinderCephContext(CephContext):
def __call__(self):
ctxt = super(CinderCephContext, self).__call__()
# NOTE: If "rbd-mirroring-mode" is set to "image" we are going
# to ignore default 'rbd_features' that are set in the context
if config('rbd-mirror-mode') == "image":
ctxt.pop('rbd_features', None)
return ctxt