plugins/ceph: Add common pool creation method

The new helper supports to optionally retrieve common
configuration options for BlueStore Compression.

Fix ordering of Ceph class composition. Both the CephCharm and the
fake charm class used in the unit test had the wrong order for the
composition making it impossible to override already existing
methods inherited from OpenStackCharm.

Change-Id: I9fb543f297522c7217acdcfa950bb2810b26c4a0
This commit is contained in:
Frode Nordahl 2020-09-21 12:38:30 +02:00
parent d0d3e2b1ea
commit af1dd4cdee
No known key found for this signature in database
GPG Key ID: 6A5D59A3BA48373F
2 changed files with 112 additions and 4 deletions

View File

@ -23,6 +23,7 @@ import charms_openstack.charm
from charms_openstack.charm.classes import SNAP_PATH_PREFIX_FORMAT
import charmhelpers.core as ch_core
import charmhelpers.contrib.openstack.context as ch_context
import charmhelpers.contrib.openstack.policyd as ch_policyd
@ -216,9 +217,78 @@ class BaseOpenStackCephCharm(object):
except OSError:
return ''
@staticmethod
def _get_bluestore_compression():
"""Get BlueStore Compression charm configuration if present.
class CephCharm(charms_openstack.charm.OpenStackCharm,
BaseOpenStackCephCharm):
:returns: Dictionary of options suitable for passing on as keyword
arguments or None.
:rtype: Optional[Dict[str,any]]
:raises: ValueError
"""
try:
bluestore_compression = (
ch_context.CephBlueStoreCompressionContext())
bluestore_compression.validate()
except KeyError:
# The charm does not have BlueStore Compression options defined
bluestore_compression = None
if bluestore_compression:
return bluestore_compression.get_kwargs()
def states_to_check(self, required_relations=None):
"""Augment states to check handling.
Validates Ceph specific configuration options and adds end user
feedback through juju status.
:param required_relations: List of relations which overrides
self.relations
:type required_relations: Optional[List[str]]
:returns: Map of relations and their states to check
:rtype: Dict[str,List[Tuple[str,str,str]]]
"""
states_to_check = super().states_to_check(
required_relations=required_relations)
try:
self._get_bluestore_compression()
except ValueError as e:
# we add a made up relation to have the library set the status for
# us.
states_to_check['charm.bluestore_compression'] = [
('charm.bluestore_compression',
'blocked',
'Invalid configuration: {}'.format(str(e))),
]
return states_to_check
def create_pool(self, ceph_interface):
"""Request pool for service.
:param ceph_interface: Ceph interface instance
:type ceph_interface: CephRequires
"""
try:
bluestore_compression = self._get_bluestore_compression()
except ValueError as e:
# One or more of the values provided for the configuration options
# is invalid, do not attempt to create pool. The end user will be
# informed about the condition through juju status
# (see the ``states_to_check`` method above).
ch_core.hookenv.log('Invalid value(s) provided for Ceph BlueStore '
'compression: "{}"'
.format(str(e)))
return
kwargs = {
'name': self.name,
}
if bluestore_compression:
kwargs.update(bluestore_compression)
ceph_interface.create_replicated_pool(**kwargs)
class CephCharm(BaseOpenStackCephCharm,
charms_openstack.charm.OpenStackCharm):
"""Class for charms deploying Ceph services.
It provides useful defaults to make release detection work when no

View File

@ -13,8 +13,8 @@ TEST_CONFIG = {'config': True,
class FakeOpenStackCephConsumingCharm(
chm.OpenStackCharm,
cpl.BaseOpenStackCephCharm):
cpl.BaseOpenStackCephCharm,
chm.OpenStackCharm):
abstract_class = True
@ -134,6 +134,44 @@ class TestOpenStackCephConsumingCharm(BaseOpenStackCharmTest):
self.remove.side_effect = OSError
self.assertEqual(self.target.delete_ceph_keyring(), '')
def test__get_bluestore_compression(self):
self.patch_object(cpl.ch_context, 'CephBlueStoreCompressionContext')
bluestore_compression = mock.MagicMock()
expect = {'fake': 'value'}
bluestore_compression.get_kwargs.return_value = expect
self.CephBlueStoreCompressionContext.return_value = (
bluestore_compression)
bluestore_compression.validate.side_effect = KeyError
self.assertEquals(self.target._get_bluestore_compression(), None)
bluestore_compression.validate.side_effect = None
self.assertDictEqual(
self.target._get_bluestore_compression(),
expect)
def test_states_to_check(self):
self.patch_object(chm.OpenStackCharm, 'states_to_check',
name='parent_states_to_check')
expect = {'fake': [('state', 'message')]}
self.parent_states_to_check.return_value = expect
self.patch_target('_get_bluestore_compression')
self.assertDictEqual(self.target.states_to_check(), expect)
self._get_bluestore_compression.side_effect = ValueError
result = self.target.states_to_check()
self.assertIn('fake', result)
self.assertIn('charm.bluestore_compression', result)
def test_create_pool(self):
ceph_interface = mock.MagicMock()
self.patch_target('_get_bluestore_compression')
self._get_bluestore_compression.side_effect = ValueError
self.target.create_pool(ceph_interface)
self.assertFalse(ceph_interface.create_replicated_pool.called)
self._get_bluestore_compression.side_effect = None
self._get_bluestore_compression.return_value = {'fake': 'value'}
self.target.create_pool(ceph_interface)
ceph_interface.create_replicated_pool.assert_called_once_with(
name='charmname', fake='value')
class TestCephCharm(BaseOpenStackCharmTest):