Handle RBD mirroring mode set in the relation

Change-Id: I423eb38f5197879c5f8f7999acb11ece3d26a6a4
Co-authored-by: Marius Oprin <morpin@cloudbasesolutions.com>
Signed-off-by: Marius Oprin <moprin@cloudbasesolutions.com>
This commit is contained in:
Ionut Balutoiu 2020-10-27 16:59:07 +00:00 committed by Marius
parent 3b1527df25
commit 3562e11bda
4 changed files with 106 additions and 13 deletions

View File

@ -126,8 +126,8 @@ class CephRBDMirrorCharm(charms_openstack.plugins.CephCharm):
universal_newlines=True)
return json.loads(output)
def mirror_pool_enabled(self, pool):
return self._mirror_pool_info(pool).get('mode', None) == 'pool'
def mirror_pool_enabled(self, pool, mode='pool'):
return self._mirror_pool_info(pool).get('mode', None) == mode
def mirror_pool_has_peers(self, pool):
return len(self._mirror_pool_info(pool).get('peers', [])) > 0
@ -151,9 +151,9 @@ class CephRBDMirrorCharm(charms_openstack.plugins.CephCharm):
stats['image_states'][state] += value
return stats
def mirror_pool_enable(self, pool):
def mirror_pool_enable(self, pool, mode='pool'):
base_cmd = ['rbd', '--id', self.ceph_id, 'mirror', 'pool']
subprocess.check_call(base_cmd + ['enable', pool, 'pool'])
subprocess.check_call(base_cmd + ['enable', pool, mode])
subprocess.check_call(base_cmd + ['peer', 'add', pool,
'client.{}@remote'
.format(self.ceph_id)])
@ -176,6 +176,32 @@ class CephRBDMirrorCharm(charms_openstack.plugins.CephCharm):
result_set.add(op['name'])
return result_set
def pool_mirroring_mode(self, pool, broker_requests=[]):
"""Get the Ceph RBD mirroring mode for the pool.
Checks if the pool RBD mirroring mode was explicitly set as part of
the 'create-pool' operation into any of the given broker requests.
If this is true, its value is returned, otherwise the default 'pool'
mirroring mode is used.
:param pool: Pool name
:type pool: str
:param broker_requests: List of broker requests
:type broker_requests: List[ch_ceph.CephBrokerRq]
:returns: Ceph RBD mirroring mode
:rtype: str
"""
default_mirroring_mode = 'pool'
for rq in broker_requests:
if not rq:
continue
assert rq.api_version == 1
for op in rq.ops:
if op['op'] == 'create-pool' and op['name'] == pool:
return op.get(
'rbd-mirroring-mode', default_mirroring_mode)
return default_mirroring_mode
def collapse_and_filter_broker_requests(self, broker_requests,
allowed_ops, require_vp=None):
"""Extract allowed ops from broker requests into one collapsed request.

View File

@ -117,12 +117,16 @@ def configure_pools():
pools_in_rq |= charm_instance.pools_in_broker_request(
remote_rq) if remote_rq else set()
for pool, attrs in charm_instance.eligible_pools(local.pools).items():
if not (charm_instance.mirror_pool_enabled(pool) and
charm_instance.mirror_pool_has_peers(pool)):
pool_mirroring_mode = charm_instance.pool_mirroring_mode(
pool, [rq, remote_rq])
mirroring_enabled = charm_instance.mirror_pool_enabled(
pool, pool_mirroring_mode)
has_peers = charm_instance.mirror_pool_has_peers(pool)
if not (mirroring_enabled and has_peers):
ch_core.hookenv.log('Enabling mirroring for pool "{}"'
.format(pool),
level=ch_core.hookenv.INFO)
charm_instance.mirror_pool_enable(pool)
charm_instance.mirror_pool_enable(pool, pool_mirroring_mode)
if (pool not in pools_in_rq and
'erasure_code_profile' not in attrs['parameters']):
# A pool exists that there is no broker request for which means

View File

@ -157,11 +157,17 @@ class TestCephRBDMirrorHandlers(test_utils.PatchHelper):
self.patch_object(handlers.reactive, 'endpoint_from_flag')
endpoint_local = mock.MagicMock()
endpoint_remote = mock.MagicMock()
self.crm_charm.collapse_and_filter_broker_requests.side_effect = [
endpoint_local, endpoint_remote]
endpoint_local.endpoint_name = 'ceph-local'
endpoint_local.pools = {
'cinder-ceph': {
'applications': {'rbd': {}},
'parameters': {'pg_num': 42, 'size': 3},
'parameters': {
'pg_num': 42,
'size': 3,
'rbd-mirroring-mode': 'pool'
},
'quota': {'max_bytes': 1024, 'max_objects': 51},
},
}
@ -170,6 +176,8 @@ class TestCephRBDMirrorHandlers(test_utils.PatchHelper):
endpoint_remote]
self.crm_charm.eligible_pools.return_value = endpoint_local.pools
self.crm_charm.mirror_pool_enabled.return_value = False
self.crm_charm.pool_mirroring_mode.return_value = 'pool'
handlers.configure_pools()
self.endpoint_from_flag.assert_has_calls([
mock.call('ceph-local.available'),
@ -177,8 +185,10 @@ class TestCephRBDMirrorHandlers(test_utils.PatchHelper):
])
self.crm_charm.eligible_pools.assert_called_once_with(
endpoint_local.pools)
self.crm_charm.pool_mirroring_mode.assert_called_once_with(
'cinder-ceph', [endpoint_local, endpoint_remote])
self.crm_charm.mirror_pool_enabled.assert_called_once_with(
'cinder-ceph')
'cinder-ceph', 'pool')
self.crm_charm.mirror_pool_enable.assert_called_once_with(
'cinder-ceph')
endpoint_remote.maybe_send_rq.assert_called_once_with(mock.ANY)
'cinder-ceph', 'pool')
endpoint_remote.maybe_send_rq.assert_called_once_with(endpoint_local)

View File

@ -14,6 +14,7 @@
import collections
import mock
import json
import subprocess
import charms_openstack.test_utils as test_utils
@ -92,10 +93,10 @@ class TestCephRBDMirrorCharm(Helper):
'client.rbd-mirror.juju-c50b1a-zaza-4ce96f1e7e43-12'}]
}
crmc._mirror_pool_info = _mirror_pool_info
self.assertTrue(crmc.mirror_pool_enabled('apool'))
self.assertTrue(crmc.mirror_pool_enabled('apool', mode='pool'))
_mirror_pool_info.assert_called_once_with('apool')
_mirror_pool_info.return_value = {'mode': 'disabled'}
self.assertFalse(crmc.mirror_pool_enabled('apool'))
self.assertFalse(crmc.mirror_pool_enabled('apool', mode='pool'))
def test_mirror_pool_has_peers(self):
self.patch_object(ceph_rbd_mirror.socket, 'gethostname')
@ -192,3 +193,55 @@ class TestCephRBDMirrorCharm(Helper):
{'app-name': 'rbd', 'name': 'pool-rq2', 'op': 'create-pool',
'someotherkey': 'value'})
self.assertTrue(len(rq.ops) == 1)
def test_pool_mirroring_mode(self):
self.patch_object(ceph_rbd_mirror.ch_ceph, 'CephBrokerRq')
class FakeCephBrokerRq(object):
def __init__(self, raw_request_data=None):
request_data = json.loads(raw_request_data)
self.api_version = request_data['api-version']
self.request_id = request_data['request-id']
self.set_ops(request_data['ops'])
def set_ops(self, ops):
self.ops = ops
def add_op(self, op):
self.ops.append(op)
self.CephBrokerRq.side_effect = FakeCephBrokerRq
brq1_data = json.dumps({
'api-version': 1,
'request-id': 'broker_rq1',
'ops': [
{
'op': 'create-pool',
'name': 'pool-rq0',
'app-name': 'rbd-pool',
'rbd-mirroring-mode': 'pool'
},
]
})
brq2_data = json.dumps({
'api-version': 1,
'request-id': 'broker_rq2',
'ops': [
{
'op': 'create-pool',
'name': 'pool-rq1',
'app-name': 'rbd-image',
'rbd-mirroring-mode': 'image'
},
]
})
brq1 = self.CephBrokerRq(raw_request_data=brq1_data)
brq2 = self.CephBrokerRq(raw_request_data=brq2_data)
broker_requests = [brq1, brq2, None]
crmc = ceph_rbd_mirror.CephRBDMirrorCharm()
rq0 = crmc.pool_mirroring_mode('pool-rq0', broker_requests)
self.assertEqual('pool', rq0)
rq1 = crmc.pool_mirroring_mode('pool-rq1', broker_requests)
self.assertEqual('image', rq1)