Changed way of providing RBD keyring from keyring_path to client token

In created temporary file with RBD configuration there was provided
a path for keyring file. It could work only when both system e.g.
cinder-volume and host had exact same Ceph configuration, but there was no
guarantee for that.
Providing Ceph token will help avoid such situations.

Partial-Bug: #1668304
Change-Id: I465828dec58ab2110b33743a10e6fc518b5c85ff
This commit is contained in:
Daniel Pawlik 2017-05-16 13:29:04 +02:00
parent 67e1a39a7e
commit 13f2765863
2 changed files with 48 additions and 17 deletions

View File

@ -69,25 +69,31 @@ class RBDConnector(base.BaseLinuxConnector):
return host
return list(map(_sanitize_host, hosts))
def _check_or_get_keyring_contents(self, keyring, cluster_name, user):
try:
if keyring is None:
keyring_path = ("/etc/ceph/%s.client.%s.keyring" %
(cluster_name, user))
with open(keyring_path, 'r') as keyring_file:
keyring = keyring_file.read()
return keyring
except IOError:
msg = (_("Keyring path %s is not readable.") % (keyring_path))
raise exception.BrickException(msg=msg)
def _create_ceph_conf(self, monitor_ips, monitor_ports,
cluster_name, user, keyring_path):
cluster_name, user, keyring):
monitors = ["%s:%s" % (ip, port) for ip, port in
zip(self._sanitize_mon_hosts(monitor_ips), monitor_ports)]
mon_hosts = "mon_host = %s" % (','.join(monitors))
client_section = "[client.%s]" % user
if keyring_path is None:
keyring = ("keyring = /etc/ceph/%s.client.%s.keyring" %
(cluster_name, user))
else:
keyring = "keyring = %s" % keyring_path
keyring = self._check_or_get_keyring_contents(keyring, cluster_name,
user)
try:
fd, ceph_conf_path = tempfile.mkstemp(prefix="brickrbd_")
with os.fdopen(fd, 'w') as conf_file:
conf_file.writelines([mon_hosts, "\n",
client_section, "\n", keyring, "\n"])
conf_file.writelines([mon_hosts, "\n", keyring, "\n"])
return ceph_conf_path
except IOError:
msg = (_("Failed to write data to %s.") % (ceph_conf_path))
@ -100,14 +106,14 @@ class RBDConnector(base.BaseLinuxConnector):
cluster_name = connection_properties.get('cluster_name')
monitor_ips = connection_properties.get('hosts')
monitor_ports = connection_properties.get('ports')
keyring_path = connection_properties.get('keyring')
keyring = connection_properties.get('keyring')
except IndexError:
msg = _("Connect volume failed, malformed connection properties")
raise exception.BrickException(msg=msg)
conf = self._create_ceph_conf(monitor_ips, monitor_ports,
str(cluster_name), user,
keyring_path)
keyring)
try:
rbd_client = linuxrbd.RBDClient(user, pool, conffile=conf,
rbd_cluster_name=str(cluster_name))

View File

@ -34,7 +34,7 @@ class RBDConnectorTestCase(test_connector.ConnectorTestCase):
self.clustername = 'fake_ceph'
self.hosts = ['192.168.10.2']
self.ports = ['6789']
self.keyring = '/etc/ceph/ceph.client.cinder.keyring'
self.keyring = "[client.cinder]\n key = test\n"
self.connection_properties = {
'auth_username': self.user,
@ -42,6 +42,7 @@ class RBDConnectorTestCase(test_connector.ConnectorTestCase):
'cluster_name': self.clustername,
'hosts': self.hosts,
'ports': self.ports,
'keyring': self.keyring,
}
def test_get_search_path(self):
@ -100,16 +101,40 @@ class RBDConnectorTestCase(test_connector.ConnectorTestCase):
@mock.patch('os_brick.initiator.linuxrbd.rados')
@mock.patch.object(rbd.RBDConnector, '_create_ceph_conf')
@mock.patch('os.path.exists')
def test_custom_keyring(self, mock_path, mock_conf, mock_rados, mock_rbd):
def test_provided_keyring(self, mock_path, mock_conf, mock_rados,
mock_rbd):
conn = rbd.RBDConnector(None)
mock_path.return_value = False
mock_conf.return_value = "/tmp/fake_dir/fake_ceph.conf"
custom_keyring_path = "/foo/bar/baz"
self.connection_properties['keyring'] = custom_keyring_path
self.connection_properties['keyring'] = self.keyring
conn.connect_volume(self.connection_properties)
mock_conf.assert_called_once_with(self.hosts, self.ports,
self.clustername, self.user,
custom_keyring_path)
self.keyring)
def test_keyring_is_none(self):
conn = rbd.RBDConnector(None)
keyring = None
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('os_brick.initiator.connectors.rbd.open', mockopen,
create=True):
self.assertEqual(
conn._check_or_get_keyring_contents(keyring, 'cluster',
'user'), keyring_data)
def test_keyring_raise_error(self):
conn = rbd.RBDConnector(None)
keyring = None
mockopen = mock.mock_open()
mockopen.return_value = ""
with mock.patch('os_brick.initiator.connectors.rbd.open', mockopen,
create=True) as mock_keyring_file:
mock_keyring_file.side_effect = IOError
self.assertRaises(exception.BrickException,
conn._check_or_get_keyring_contents, keyring,
'cluster', 'user')
@ddt.data((['192.168.1.1', '192.168.1.2'],
['192.168.1.1', '192.168.1.2']),