Add custom keyring when initializing RBD connection

Added RBD keyring configuration parameter which will help administrator
set an custom keyring path to the Ceph cluster.

Closes-bug: #1668304

Change-Id: I263cc10dc877b20bbc205ea55173ad3878687ea1
This commit is contained in:
Daniel Pawlik 2017-04-13 15:32:05 +00:00
parent ffe7d919d8
commit d0520a07e9
3 changed files with 82 additions and 20 deletions

View File

@ -155,6 +155,7 @@ class RBDTestCase(test.TestCase):
self.cfg.rbd_cluster_name = 'nondefault'
self.cfg.rbd_pool = 'rbd'
self.cfg.rbd_ceph_conf = '/etc/ceph/my_ceph.conf'
self.cfg.rbd_keyring_conf = '/etc/ceph/my_ceph.client.keyring'
self.cfg.rbd_secret_uuid = None
self.cfg.rbd_user = 'cinder'
self.cfg.volume_backend_name = None
@ -1149,13 +1150,23 @@ class RBDTestCase(test.TestCase):
self.assertEqual((hosts, ports), self.driver._get_mon_addrs())
@common_mocks
def test_initialize_connection(self):
hosts = ['::1', '::1', '::1', '127.0.0.1', 'example.com']
ports = ['6789', '6790', '6791', '6792', '6791']
def _initialize_connection_helper(self, expected, hosts, ports):
with mock.patch.object(self.driver, '_get_mon_addrs') as \
mock_get_mon_addrs:
mock_get_mon_addrs.return_value = (hosts, ports)
actual = self.driver.initialize_connection(self.volume_a, None)
self.assertDictEqual(expected, actual)
self.assertTrue(mock_get_mon_addrs.called)
@mock.patch.object(cinder.volume.drivers.rbd.RBDDriver,
'_get_keyring_contents')
def test_initialize_connection(self, mock_keyring):
hosts = ['::1', '::1', '::1', '127.0.0.1', 'example.com']
ports = ['6789', '6790', '6791', '6792', '6791']
keyring_data = "[client.cinder]\n key = test\n"
mock_keyring.return_value = keyring_data
expected = {
'driver_volume_type': 'rbd',
@ -1171,11 +1182,39 @@ class RBDTestCase(test.TestCase):
'secret_uuid': None,
'volume_id': self.volume_a.id,
'discard': True,
'keyring': keyring_data,
}
}
actual = self.driver.initialize_connection(self.volume_a, None)
self.assertDictEqual(expected, actual)
self.assertTrue(mock_get_mon_addrs.called)
self._initialize_connection_helper(expected, hosts, ports)
# Check how it will work with empty keyring path
mock_keyring.return_value = None
expected['data']['keyring'] = None
self._initialize_connection_helper(expected, hosts, ports)
def test__get_keyring_contents_no_config_file(self):
self.cfg.rbd_keyring_conf = ''
self.assertIsNone(self.driver._get_keyring_contents())
@mock.patch('os.path.isfile')
def test__get_keyring_contents_read_file(self, mock_isfile):
mock_isfile.return_value = True
keyring_data = "[client.cinder]\n key = test\n"
mockopen = mock.mock_open(read_data=keyring_data)
mockopen.return_value.__exit__ = mock.Mock()
with mock.patch('cinder.volume.drivers.rbd.open', mockopen,
create=True):
self.assertEqual(self.driver._get_keyring_contents(), keyring_data)
@mock.patch('os.path.isfile')
def test__get_keyring_contents_raise_error(self, mock_isfile):
mock_isfile.return_value = True
mockopen = mock.mock_open()
mockopen.return_value.__exit__ = mock.Mock()
with mock.patch('cinder.volume.drivers.rbd.open', mockopen,
create=True) as mock_keyring_file:
mock_keyring_file.side_effect = IOError
self.assertIsNone(self.driver._get_keyring_contents())
@ddt.data({'rbd_chunk_size': 1, 'order': 20},
{'rbd_chunk_size': 8, 'order': 23},

View File

@ -59,6 +59,9 @@ RBD_OPTS = [
cfg.StrOpt('rbd_ceph_conf',
default='', # default determined by librados
help='Path to the ceph configuration file'),
cfg.StrOpt('rbd_keyring_conf',
default='',
help='Path to the ceph keyring file'),
cfg.BoolOpt('rbd_flatten_volume_from_snapshot',
default=False,
help='Flatten volumes created from snapshots to remove '
@ -1023,6 +1026,20 @@ class RBDDriver(driver.CloneableImageVD,
"""Removes an export for a logical volume."""
pass
def _get_keyring_contents(self):
# NOTE(danpawlik) If keyring is not provided in Cinder configuration,
# os-brick library will take keyring from default path.
keyring_file = self.configuration.rbd_keyring_conf
keyring_data = None
try:
if os.path.isfile(keyring_file):
with open(keyring_file, 'r') as k_file:
keyring_data = k_file.read()
except IOError:
LOG.debug('Cannot read RBD keyring file: %s.', keyring_file)
return keyring_data
def initialize_connection(self, volume, connector):
hosts, ports = self._get_mon_addrs()
data = {
@ -1039,6 +1056,7 @@ class RBDDriver(driver.CloneableImageVD,
'secret_uuid': self.configuration.rbd_secret_uuid,
'volume_id': volume.id,
"discard": True,
'keyring': self._get_keyring_contents(),
}
}
LOG.debug('connection data: %s', data)

View File

@ -0,0 +1,5 @@
---
features:
- |
Added RBD keyring configuration parameter ``rbd_keyring_conf`` to define
custom path of Ceph keyring file.