diff --git a/hooks/ceph_broker.py b/hooks/ceph_broker.py index e162dcb..bd23d43 100644 --- a/hooks/ceph_broker.py +++ b/hooks/ceph_broker.py @@ -12,6 +12,7 @@ from charmhelpers.core.hookenv import ( ) from charmhelpers.contrib.storage.linux.ceph import ( create_pool, + get_osds, pool_exists, ) @@ -83,12 +84,26 @@ def process_requests_v1(reqs): log(msg, level=ERROR) return {'exit-code': 1, 'stderr': msg} + # Mandatory params pool = params['pool'] replicas = params['replicas'] + + # Optional params + pg_num = req.get('pg_num') + if pg_num: + # Cap pg_num to max allowed just in case. + osds = get_osds(svc) + if osds: + pg_num = min(pg_num, (len(osds) * 100 // replicas)) + + # Ensure string + pg_num = str(pg_num) + if not pool_exists(service=svc, name=pool): log("Creating pool '%s' (replicas=%s)" % (pool, replicas), level=INFO) - create_pool(service=svc, name=pool, replicas=replicas) + create_pool(service=svc, name=pool, replicas=replicas, + pg_num=pg_num) else: log("Pool '%s' already exists - skipping create" % (pool), level=DEBUG) diff --git a/hooks/ceph_hooks.py b/hooks/ceph_hooks.py index 9c8c89a..518830c 100755 --- a/hooks/ceph_hooks.py +++ b/hooks/ceph_hooks.py @@ -316,20 +316,31 @@ def osd_relation(relid=None): log('mon cluster not in quorum - deferring fsid provision') +@hooks.hook('radosgw-relation-changed') @hooks.hook('radosgw-relation-joined') def radosgw_relation(relid=None): # Install radosgw for admin tools apt_install(packages=filter_installed_packages(['radosgw'])) + + """Process broker request(s).""" if ceph.is_quorum(): - log('mon cluster in quorum - providing radosgw with keys') - data = { - 'fsid': config('fsid'), - 'radosgw_key': ceph.get_radosgw_key(), - 'auth': config('auth-supported'), - 'ceph-public-address': get_public_addr(), - } - relation_set(relation_id=relid, - relation_settings=data) + settings = relation_get(rid=relid) + if 'broker_req' in settings: + if not ceph.is_leader(): + log("Not leader - ignoring broker request", level=DEBUG) + else: + rsp = process_requests(settings['broker_req']) + unit_id = remote_unit().replace('/', '-') + unit_response_key = 'broker-rsp-' + unit_id + log('mon cluster in quorum - providing radosgw with keys') + data = { + 'fsid': config('fsid'), + 'radosgw_key': ceph.get_radosgw_key(), + 'auth': config('auth-supported'), + 'ceph-public-address': get_public_addr(), + unit_response_key: rsp, + } + relation_set(relation_id=relid, relation_settings=data) else: log('mon cluster not in quorum - deferring key provision') diff --git a/hooks/radosgw-relation-changed b/hooks/radosgw-relation-changed new file mode 120000 index 0000000..52d9663 --- /dev/null +++ b/hooks/radosgw-relation-changed @@ -0,0 +1 @@ +ceph_hooks.py \ No newline at end of file diff --git a/unit_tests/test_ceph_broker.py b/unit_tests/test_ceph_broker.py index fc69817..8f08cdc 100644 --- a/unit_tests/test_ceph_broker.py +++ b/unit_tests/test_ceph_broker.py @@ -53,7 +53,47 @@ class CephBrokerTestCase(unittest.TestCase): rc = ceph_broker.process_requests(reqs) mock_pool_exists.assert_called_with(service='admin', name='foo') mock_create_pool.assert_called_with(service='admin', name='foo', - replicas=3) + replicas=3, pg_num=None) + self.assertEqual(json.loads(rc), {'exit-code': 0}) + + @mock.patch('ceph_broker.get_osds') + @mock.patch('ceph_broker.create_pool') + @mock.patch('ceph_broker.pool_exists') + @mock.patch('ceph_broker.log') + def test_process_requests_create_pool_w_pg_num(self, mock_log, + mock_pool_exists, + mock_create_pool, + mock_get_osds): + mock_get_osds.return_value = [0, 1, 2] + mock_pool_exists.return_value = False + reqs = json.dumps({'api-version': 1, + 'ops': [{'op': 'create-pool', 'name': + 'foo', 'replicas': 3, + 'pg_num': 100}]}) + rc = ceph_broker.process_requests(reqs) + mock_pool_exists.assert_called_with(service='admin', name='foo') + mock_create_pool.assert_called_with(service='admin', name='foo', + replicas=3, pg_num='100') + self.assertEqual(json.loads(rc), {'exit-code': 0}) + + @mock.patch('ceph_broker.get_osds') + @mock.patch('ceph_broker.create_pool') + @mock.patch('ceph_broker.pool_exists') + @mock.patch('ceph_broker.log') + def test_process_requests_create_pool_w_pg_num_capped(self, mock_log, + mock_pool_exists, + mock_create_pool, + mock_get_osds): + mock_get_osds.return_value = [0, 1, 2] + mock_pool_exists.return_value = False + reqs = json.dumps({'api-version': 1, + 'ops': [{'op': 'create-pool', 'name': + 'foo', 'replicas': 3, + 'pg_num': 300}]}) + rc = ceph_broker.process_requests(reqs) + mock_pool_exists.assert_called_with(service='admin', name='foo') + mock_create_pool.assert_called_with(service='admin', name='foo', + replicas=3, pg_num='100') self.assertEqual(json.loads(rc), {'exit-code': 0}) @mock.patch('ceph_broker.create_pool') @@ -84,7 +124,7 @@ class CephBrokerTestCase(unittest.TestCase): rc = ceph_broker.process_requests(reqs) mock_pool_exists.assert_called_with(service='admin', name='foo') mock_create_pool.assert_called_with(service='admin', name='foo', - replicas=3) + replicas=3, pg_num=None) self.assertEqual(json.loads(rc)['exit-code'], 0) self.assertEqual(json.loads(rc)['request-id'], '1ef5aede')