From: Josh Durgin Date: Sat, 25 May 2013 01:18:30 +0000 (-0700) Subject: rbd: send ceph monitor addresses with connection info X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=483b84e42b90f2ffe0a09f5e38b85eb64cf8f7d9;p=openstack-build%2Fcinder-build.git rbd: send ceph monitor addresses with connection info Previously we relied on a ceph configuration file on the compute host for this information. Sending the info directly from cinder makes more complex setups with multiple ceph clusters talking to the same compute hosts possible. Refresh the monitor addresses for each initialize_connection() call, since monitors may be added or removed while cinder-volume is running. Fixes: bug 1077817 Signed-off-by: Josh Durgin Change-Id: I34a1fa16ce1f4524ba25832faf3129303e755100 --- diff --git a/cinder/tests/test_rbd.py b/cinder/tests/test_rbd.py index 54b6ffffa..4942d0241 100644 --- a/cinder/tests/test_rbd.py +++ b/cinder/tests/test_rbd.py @@ -35,6 +35,34 @@ from cinder.volume.drivers.rbd import VERSION as DRIVER_VERSION LOG = logging.getLogger(__name__) +CEPH_MON_DUMP = """dumped monmap epoch 1 +{ "epoch": 1, + "fsid": "33630410-6d93-4d66-8e42-3b953cf194aa", + "modified": "2013-05-22 17:44:56.343618", + "created": "2013-05-22 17:44:56.343618", + "mons": [ + { "rank": 0, + "name": "a", + "addr": "[::1]:6789\/0"}, + { "rank": 1, + "name": "b", + "addr": "[::1]:6790\/0"}, + { "rank": 2, + "name": "c", + "addr": "[::1]:6791\/0"}, + { "rank": 3, + "name": "d", + "addr": "127.0.0.1:6792\/0"}, + { "rank": 4, + "name": "e", + "addr": "example.com:6791\/0"}], + "quorum": [ + 0, + 1, + 2]} +""" + + class FakeImageService: def download(self, context, image_id, path): pass @@ -190,6 +218,34 @@ class RBDTestCase(test.TestCase): actual = self.driver.get_volume_stats(True) self.assertDictMatch(expected, actual) + def test_get_mon_addrs(self): + self.stubs.Set(self.driver, '_execute', + lambda *a: (CEPH_MON_DUMP, '')) + hosts = ['::1', '::1', '::1', '127.0.0.1', 'example.com'] + ports = ['6789', '6790', '6791', '6792', '6791'] + self.assertEqual((hosts, ports), self.driver._get_mon_addrs()) + + def test_initialize_connection(self): + name = 'volume-00000001' + hosts = ['::1', '::1', '::1', '127.0.0.1', 'example.com'] + ports = ['6789', '6790', '6791', '6792', '6791'] + self.stubs.Set(self.driver, '_get_mon_addrs', lambda: (hosts, ports)) + expected = { + 'driver_volume_type': 'rbd', + 'data': { + 'name': '%s/%s' % (self.configuration.rbd_pool, + name), + 'hosts': hosts, + 'ports': ports, + 'auth_enabled': False, + 'auth_username': None, + 'secret_type': 'ceph', + 'secret_uuid': None, + } + } + actual = self.driver.initialize_connection(dict(name=name), None) + self.assertDictMatch(expected, actual) + class ManagedRBDTestCase(DriverTestCase): driver_name = "cinder.volume.drivers.rbd.RBDDriver" diff --git a/cinder/volume/drivers/rbd.py b/cinder/volume/drivers/rbd.py index f31c4cdae..1a06961ad 100644 --- a/cinder/volume/drivers/rbd.py +++ b/cinder/volume/drivers/rbd.py @@ -65,6 +65,23 @@ class RBDDriver(driver.VolumeDriver): self.configuration.rbd_pool) raise exception.VolumeBackendAPIException(data=exception_message) + def _get_mon_addrs(self): + args = ['ceph', 'mon', 'dump', '--format=json'] + out, _ = self._execute(*args) + lines = out.split('\n') + if lines[0].startswith('dumped monmap epoch'): + lines = lines[1:] + monmap = json.loads('\n'.join(lines)) + addrs = [mon['addr'] for mon in monmap['mons']] + hosts = [] + ports = [] + for addr in addrs: + host_port = addr[:addr.rindex('/')] + host, port = host_port.rsplit(':', 1) + hosts.append(host.strip('[]')) + ports.append(port) + return hosts, ports + def _update_volume_stats(self): stats = {'vendor_name': 'Open Source', 'driver_version': VERSION, @@ -199,11 +216,14 @@ class RBDDriver(driver.VolumeDriver): pass def initialize_connection(self, volume, connector): + hosts, ports = self._get_mon_addrs() return { 'driver_volume_type': 'rbd', 'data': { 'name': '%s/%s' % (self.configuration.rbd_pool, volume['name']), + 'hosts': hosts, + 'ports': ports, 'auth_enabled': (self.configuration.rbd_secret_uuid is not None), 'auth_username': self.configuration.rbd_user,