diff --git a/hooks/ceph_hooks.py b/hooks/ceph_hooks.py index 7458887..960eeba 100755 --- a/hooks/ceph_hooks.py +++ b/hooks/ceph_hooks.py @@ -18,6 +18,7 @@ from charmhelpers.core.hookenv import ( log, DEBUG, config, + is_leader, relation_ids, related_units, relation_get, @@ -44,11 +45,7 @@ from ceph_broker import ( process_requests ) -from utils import ( - get_public_addr, - get_unit_hostname, -) - +from utils import get_unit_hostname from charmhelpers.contrib.hardening.harden import harden hooks = Hooks() @@ -137,12 +134,12 @@ def radosgw_relation(relid=None, unit=None): if ready(): log('mon cluster in quorum and osds related ' '- providing radosgw with keys') - public_addr = get_public_addr() + ceph_addrs = config('monitor-hosts') data = { 'fsid': config('fsid'), 'radosgw_key': ceph.get_radosgw_key(), - 'auth': 'cephx', - 'ceph-public-address': public_addr, + 'auth': config('auth-supported'), + 'ceph-public-address': ceph_addrs, } settings = relation_get(rid=relid, unit=unit) @@ -153,6 +150,7 @@ def radosgw_relation(relid=None, unit=None): unit_response_key = 'broker-rsp-' + unit_id data[unit_response_key] = rsp + log('relation_set (%s): %s' % (relid, str(data)), level=DEBUG) relation_set(relation_id=relid, relation_settings=data) else: log('FSID or admin key not provided, please configure them') @@ -171,10 +169,12 @@ def client_relation_joined(relid=None): service_name = units[0].split('/')[0] if service_name is not None: - public_addr = get_public_addr() + ceph_addrs = config('monitor-hosts') data = {'key': ceph.get_named_key(service_name), - 'auth': 'cephx', - 'ceph-public-address': public_addr} + 'auth': config('auth-supported'), + 'ceph-public-address': ceph_addrs} + + log('relation_set (%s): %s' % (relid, str(data)), level=DEBUG) relation_set(relation_id=relid, relation_settings=data) else: @@ -187,7 +187,8 @@ def client_relation_changed(): if ready(): settings = relation_get() if 'broker_req' in settings: - if not ceph.is_leader(): + # the request is processed only by the leader as reported by juju + if not is_leader(): log("Not leader - ignoring broker request", level=DEBUG) else: rsp = process_requests(settings['broker_req']) @@ -199,6 +200,7 @@ def client_relation_changed(): 'broker_rsp': rsp, unit_response_key: rsp, } + log('relation_set: %s' % str(data), level=DEBUG) relation_set(relation_settings=data) else: log('FSID or admin key not provided, please configure them') diff --git a/unit_tests/test_ceph_hooks.py b/unit_tests/test_ceph_hooks.py new file mode 100644 index 0000000..802fce9 --- /dev/null +++ b/unit_tests/test_ceph_hooks.py @@ -0,0 +1,132 @@ +import mock +import sys + +# python-apt is not installed as part of test-requirements but is imported by +# some charmhelpers modules so create a fake import. +mock_apt = mock.MagicMock() +sys.modules['apt'] = mock_apt +mock_apt.apt_pkg = mock.MagicMock() + +mock_apt_pkg = mock.MagicMock() +sys.modules['apt_pkg'] = mock_apt_pkg +mock_apt_pkg.upstream_version = mock.MagicMock() +mock_apt_pkg.upstream_version.return_value = '10.1.2-0ubuntu1' + +import test_utils +import ceph_hooks as hooks + +CEPH_KEY = 'AQDmP6dYWto6AhAAPKMkuvdFZYPRaiboU27IsA==' +CEPH_GET_KEY = """[client.admin] + key = %s + caps mds = "allow *" + caps mon = "allow *" + caps osd = "allow *" +""" % CEPH_KEY + +TO_PATCH = [ + 'config', + 'install_alternative', + 'mkdir', + 'related_units', + 'relation_get', + 'relation_ids', + 'relation_set', + 'remote_unit', + 'render', + 'service_name', + 'log' +] + + +def fake_log(message, level=None): + print("juju-log %s: %s" % (level, message)) + + +class TestHooks(test_utils.CharmTestCase): + def setUp(self): + super(TestHooks, self).setUp(hooks, TO_PATCH) + self.service_name.return_value = 'ceph-service' + self.config.side_effect = lambda x: self.test_config.get(x) + self.remote_unit.return_value = 'client/0' + self.log.side_effect = fake_log + + @mock.patch('subprocess.check_output') + def test_radosgw_realtion(self, mock_check_output): + + settings = {'ceph-public-address': '127.0.0.1:1234 [::1]:4321', + 'radosgw_key': CEPH_KEY, + 'auth': 'cephx', + 'fsid': 'some-fsid'} + + mock_check_output.return_value = CEPH_GET_KEY + self.relation_get.return_value = {} + self.test_config.set('monitor-hosts', settings['ceph-public-address']) + self.test_config.set('fsid', settings['fsid']) + self.test_config.set('admin-key', 'some-admin-key') + hooks.radosgw_relation() + self.relation_set.assert_called_with(relation_id=None, + relation_settings=settings) + + @mock.patch('ceph.ceph_user') + @mock.patch.object(hooks, 'radosgw_relation') + @mock.patch.object(hooks, 'client_relation_joined') + def test_emit_cephconf(self, mock_client_rel, mock_rgw_rel, + mock_ceph_user): + mock_ceph_user.return_value = 'ceph-user' + self.test_config.set('monitor-hosts', '127.0.0.1:1234') + self.test_config.set('fsid', 'abc123') + self.test_config.set('admin-key', 'key123') + + def c(k): + x = {'radosgw': ['rados:1'], + 'client': ['client:1'], + 'rados:1': ['rados/1']} + return x[k] + + self.relation_ids.side_effect = c + self.related_units.side_effect = c + + hooks.emit_cephconf() + + context = {'auth_supported': self.test_config.get('auth-supported'), + 'mon_hosts': self.test_config.get('monitor-hosts'), + 'fsid': self.test_config.get('fsid'), + 'use_syslog': str(self.test_config.get( + 'use-syslog')).lower(), + 'loglevel': self.test_config.get('loglevel')} + + dirname = '/var/lib/charm/ceph-service' + self.mkdir.assert_called_with(dirname, owner='ceph-user', + group='ceph-user') + self.render.assert_any_call('ceph.conf', + '%s/ceph.conf' % dirname, + context, perms=0o644) + self.install_alternative.assert_called_with('ceph.conf', + '/etc/ceph/ceph.conf', + '%s/ceph.conf' % dirname, + 100) + keyring = 'ceph.client.admin.keyring' + context = {'admin_key': self.test_config.get('admin-key')} + self.render.assert_any_call(keyring, + '/etc/ceph/' + keyring, + context, owner='ceph-user', perms=0o600) + + mock_rgw_rel.assert_called_with(relid='rados:1', unit='rados/1') + mock_client_rel.assert_called_with('client:1') + + @mock.patch('subprocess.check_output') + def test_client_relation_joined(self, mock_check_output): + mock_check_output.return_value = CEPH_GET_KEY + self.test_config.set('monitor-hosts', '127.0.0.1:1234') + self.test_config.set('fsid', 'abc123') + self.test_config.set('admin-key', 'some-admin-key') + self.related_units.return_value = ['client/0'] + + hooks.client_relation_joined('client:1') + + data = {'key': CEPH_KEY, + 'auth': 'cephx', + 'ceph-public-address': self.test_config.get('monitor-hosts')} + + self.relation_set.assert_called_with(relation_id='client:1', + relation_settings=data)