Merge "support custom admin user and user auth"
This commit is contained in:
commit
9198755128
15
config.yaml
15
config.yaml
@ -59,3 +59,18 @@ options:
|
|||||||
.
|
.
|
||||||
Valid options are "cephx" and "none". If "none" is specified, keys will
|
Valid options are "cephx" and "none". If "none" is specified, keys will
|
||||||
still be created and deployed so that it can be enabled later.
|
still be created and deployed so that it can be enabled later.
|
||||||
|
user-keys:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
description: |
|
||||||
|
A space-separated list of <username>:<cephx-base64-key> pairs used to
|
||||||
|
lookup authentication keys for a specific user instead of trying to
|
||||||
|
create a user and a key via ceph-mon.
|
||||||
|
admin-user:
|
||||||
|
type: string
|
||||||
|
default: "client.admin"
|
||||||
|
description: |
|
||||||
|
A configurable admin user name. Used for scenarios where pools are
|
||||||
|
pre-created and the user given to charm-ceph-proxy simply needs to
|
||||||
|
check the existence of a given pool and error out if one does not
|
||||||
|
exist. Can be used in conjunction with user-keys.
|
||||||
|
@ -32,6 +32,7 @@ from charmhelpers.core.hookenv import (
|
|||||||
cached,
|
cached,
|
||||||
status_set,
|
status_set,
|
||||||
WARNING,
|
WARNING,
|
||||||
|
config,
|
||||||
)
|
)
|
||||||
from charmhelpers.fetch import (
|
from charmhelpers.fetch import (
|
||||||
apt_cache
|
apt_cache
|
||||||
@ -371,14 +372,30 @@ def get_upgrade_key():
|
|||||||
return get_named_key('upgrade-osd', _upgrade_caps)
|
return get_named_key('upgrade-osd', _upgrade_caps)
|
||||||
|
|
||||||
|
|
||||||
|
def _config_user_key(name):
|
||||||
|
user_keys_list = config('user-keys')
|
||||||
|
if user_keys_list:
|
||||||
|
for ukpair in user_keys_list.split(' '):
|
||||||
|
uk = ukpair.split(':')
|
||||||
|
if len(uk) == 2:
|
||||||
|
user_type, k = uk
|
||||||
|
t, u = user_type.split('.')
|
||||||
|
if u == name:
|
||||||
|
return k
|
||||||
|
|
||||||
|
|
||||||
def get_named_key(name, caps=None):
|
def get_named_key(name, caps=None):
|
||||||
|
config_user_key = _config_user_key(name)
|
||||||
|
if config_user_key:
|
||||||
|
return config_user_key
|
||||||
|
|
||||||
caps = caps or _default_caps
|
caps = caps or _default_caps
|
||||||
cmd = [
|
cmd = [
|
||||||
"sudo",
|
"sudo",
|
||||||
"-u",
|
"-u",
|
||||||
ceph_user(),
|
ceph_user(),
|
||||||
'ceph',
|
'ceph',
|
||||||
'--name', 'client.admin',
|
'--name', config('admin-user'),
|
||||||
'--keyring',
|
'--keyring',
|
||||||
'/var/lib/ceph/mon/ceph-{}/keyring'.format(
|
'/var/lib/ceph/mon/ceph-{}/keyring'.format(
|
||||||
get_unit_hostname()
|
get_unit_hostname()
|
||||||
|
@ -86,11 +86,16 @@ def emit_cephconf():
|
|||||||
render('ceph.conf', charm_ceph_conf, cephcontext, perms=0o644)
|
render('ceph.conf', charm_ceph_conf, cephcontext, perms=0o644)
|
||||||
install_alternative('ceph.conf', '/etc/ceph/ceph.conf',
|
install_alternative('ceph.conf', '/etc/ceph/ceph.conf',
|
||||||
charm_ceph_conf, 100)
|
charm_ceph_conf, 100)
|
||||||
keyring = 'ceph.client.admin.keyring'
|
|
||||||
|
keyring_template = 'ceph.keyring'
|
||||||
|
keyring = 'ceph.{}.keyring'.format(config('admin-user'))
|
||||||
keyring_path = '/etc/ceph/' + keyring
|
keyring_path = '/etc/ceph/' + keyring
|
||||||
ctx = {'admin_key': config('admin-key')}
|
ctx = {
|
||||||
|
'admin_key': config('admin-key'),
|
||||||
|
'admin_user': config('admin-user'),
|
||||||
|
}
|
||||||
user = ceph.ceph_user()
|
user = ceph.ceph_user()
|
||||||
render(keyring, keyring_path, ctx, owner=user, perms=0o600)
|
render(keyring_template, keyring_path, ctx, owner=user, perms=0o600)
|
||||||
|
|
||||||
keyring = 'keyring'
|
keyring = 'keyring'
|
||||||
keyring_path = (
|
keyring_path = (
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
[client.admin]
|
[{{ admin_user }}]
|
||||||
key = {{admin_key}}
|
key = {{admin_key}}
|
||||||
|
|
@ -1,3 +1,3 @@
|
|||||||
[client.admin]
|
[{{ admin_user }}]
|
||||||
key = {{admin_key}}
|
key = {{admin_key}}
|
||||||
|
|
||||||
|
95
unit_tests/test_ceph.py
Normal file
95
unit_tests/test_ceph.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
import ceph
|
||||||
|
|
||||||
|
|
||||||
|
class CephTestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(CephTestCase, self).setUp()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def populated_config_side_effect(key):
|
||||||
|
return {
|
||||||
|
'user-keys':
|
||||||
|
'client.cinder-ceph:AQAij2tbMNjMOhAAqInpXQLFrltDgmYid6KXbg== '
|
||||||
|
'client.glance:AQCnjmtbuEACMxAA7joUmgLIGI4/3LKkPzUy8g== '
|
||||||
|
'client.gnocchi:AQDk7qJb0csAFRAAQqPU6HchVW3PT6ymgXdI/A== '
|
||||||
|
'client.nova-compute-kvm:'
|
||||||
|
'AQBkjmtb1hWxLxAA3UhxSblgFSCtHVoZ8W6rNQ== '
|
||||||
|
'client.radosgw.gateway:'
|
||||||
|
'AQBljmtb65mrHhAAGy9VRkfsatWVLb9EpoWDfw==',
|
||||||
|
'admin-user': 'client.myadmin'
|
||||||
|
}[key]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def empty_config_side_effect(key):
|
||||||
|
return {
|
||||||
|
'user-keys': '',
|
||||||
|
'admin-user': 'client.myadmin'
|
||||||
|
}[key]
|
||||||
|
|
||||||
|
@mock.patch('ceph.config')
|
||||||
|
def test_config_user_key_populated(self, mock_config):
|
||||||
|
user_name = 'glance'
|
||||||
|
user_key = 'AQCnjmtbuEACMxAA7joUmgLIGI4/3LKkPzUy8g=='
|
||||||
|
|
||||||
|
mock_config.side_effect = self.populated_config_side_effect
|
||||||
|
named_key = ceph._config_user_key(user_name)
|
||||||
|
self.assertEqual(user_key, named_key)
|
||||||
|
|
||||||
|
@mock.patch('ceph.config')
|
||||||
|
def test_config_empty_user_key(self, mock_config):
|
||||||
|
user_name = 'cinder-ceph'
|
||||||
|
|
||||||
|
mock_config.side_effect = self.empty_config_side_effect
|
||||||
|
named_key = ceph._config_user_key(user_name)
|
||||||
|
self.assertEqual(named_key, None)
|
||||||
|
|
||||||
|
@mock.patch('ceph.config')
|
||||||
|
def test_get_named_key_populated(self, mock_config):
|
||||||
|
user_name = 'glance'
|
||||||
|
user_key = 'AQCnjmtbuEACMxAA7joUmgLIGI4/3LKkPzUy8g=='
|
||||||
|
|
||||||
|
mock_config.side_effect = self.populated_config_side_effect
|
||||||
|
named_key = ceph.get_named_key(user_name)
|
||||||
|
|
||||||
|
self.assertEqual(user_key, named_key)
|
||||||
|
|
||||||
|
@mock.patch('subprocess.check_output')
|
||||||
|
@mock.patch('ceph.get_unit_hostname')
|
||||||
|
@mock.patch('ceph.ceph_user')
|
||||||
|
@mock.patch('ceph.config')
|
||||||
|
def test_get_named_key_empty(self, mock_config, mock_ceph_user,
|
||||||
|
mock_get_unit_hostname, mock_check_output):
|
||||||
|
user_name = 'cinder-ceph'
|
||||||
|
user_type = 'client'
|
||||||
|
admin_user = 'client.myadmin'
|
||||||
|
user_spec = '{}.{}'.format(user_type, user_name)
|
||||||
|
expected_key = 'AQCnjmtbuEACMxAA7joUmgLIGI4/3LKkPzUy8g=='
|
||||||
|
expected_output = ('[client.testuser]\n key = {}'
|
||||||
|
.format(expected_key))
|
||||||
|
caps = {
|
||||||
|
'mon': ['allow rw'],
|
||||||
|
'osd': ['allow rwx']
|
||||||
|
}
|
||||||
|
ceph_user = 'ceph'
|
||||||
|
ceph_proxy_host = 'cephproxy'
|
||||||
|
mock_get_unit_hostname.return_value = ceph_proxy_host
|
||||||
|
|
||||||
|
def check_output_side_effect(cmd):
|
||||||
|
return {
|
||||||
|
' '.join(['sudo', '-u', ceph_user, 'ceph', '--name',
|
||||||
|
admin_user,
|
||||||
|
'--keyring',
|
||||||
|
'/var/lib/ceph/mon/ceph-{}/keyring'.format(
|
||||||
|
ceph_proxy_host),
|
||||||
|
'auth', 'get-or-create', user_spec, 'mon',
|
||||||
|
'allow rw', 'osd', 'allow rwx']): expected_output
|
||||||
|
}[' '.join(cmd)]
|
||||||
|
mock_check_output.side_effect = check_output_side_effect
|
||||||
|
mock_config.side_effect = self.empty_config_side_effect
|
||||||
|
mock_ceph_user.return_value = ceph_user
|
||||||
|
named_key = ceph.get_named_key(user_name, caps)
|
||||||
|
self.assertEqual(named_key, expected_key)
|
@ -76,6 +76,7 @@ class TestHooks(test_utils.CharmTestCase):
|
|||||||
self.test_config.set('monitor-hosts', '127.0.0.1:1234')
|
self.test_config.set('monitor-hosts', '127.0.0.1:1234')
|
||||||
self.test_config.set('fsid', 'abc123')
|
self.test_config.set('fsid', 'abc123')
|
||||||
self.test_config.set('admin-key', 'key123')
|
self.test_config.set('admin-key', 'key123')
|
||||||
|
self.test_config.set('admin-user', 'client.myadmin')
|
||||||
|
|
||||||
def c(k):
|
def c(k):
|
||||||
x = {'radosgw': ['rados:1'],
|
x = {'radosgw': ['rados:1'],
|
||||||
@ -105,10 +106,15 @@ class TestHooks(test_utils.CharmTestCase):
|
|||||||
'/etc/ceph/ceph.conf',
|
'/etc/ceph/ceph.conf',
|
||||||
'%s/ceph.conf' % dirname,
|
'%s/ceph.conf' % dirname,
|
||||||
100)
|
100)
|
||||||
keyring = 'ceph.client.admin.keyring'
|
keyring_template = 'ceph.keyring'
|
||||||
context = {'admin_key': self.test_config.get('admin-key')}
|
keyring_name = 'ceph.{}.keyring'.format(
|
||||||
self.render.assert_any_call(keyring,
|
self.test_config.get('admin-user'))
|
||||||
'/etc/ceph/' + keyring,
|
context = {
|
||||||
|
'admin_key': self.test_config.get('admin-key'),
|
||||||
|
'admin_user': self.test_config.get('admin-user'),
|
||||||
|
}
|
||||||
|
self.render.assert_any_call(keyring_template,
|
||||||
|
'/etc/ceph/' + keyring_name,
|
||||||
context, owner='ceph-user', perms=0o600)
|
context, owner='ceph-user', perms=0o600)
|
||||||
|
|
||||||
mock_rgw_rel.assert_called_with(relid='rados:1', unit='rados/1')
|
mock_rgw_rel.assert_called_with(relid='rados:1', unit='rados/1')
|
||||||
|
Loading…
Reference in New Issue
Block a user