diff --git a/os_brick/initiator/connectors/rbd.py b/os_brick/initiator/connectors/rbd.py index 7c6338f50..23ca1a12d 100644 --- a/os_brick/initiator/connectors/rbd.py +++ b/os_brick/initiator/connectors/rbd.py @@ -180,12 +180,20 @@ class RBDConnector(base.BaseLinuxConnector): # NOTE(e0ne): map volume to a block device # via the rbd kernel module. pool, volume = connection_properties['name'].split('/') - cmd = ['rbd', 'map', volume, '--pool', pool] - cmd += self._get_rbd_args(connection_properties) - self._execute(*cmd, root_helper=self._root_helper, - run_as_root=True) + rbd_dev_path = RBDConnector.get_rbd_device_name(pool, volume) + if (not os.path.islink(rbd_dev_path) or + not os.path.exists(os.path.realpath(rbd_dev_path))): + cmd = ['rbd', 'map', volume, '--pool', pool] + cmd += self._get_rbd_args(connection_properties) + self._execute(*cmd, root_helper=self._root_helper, + run_as_root=True) + else: + LOG.debug('volume %(vol)s is already mapped to local' + ' device %(dev)s', + {'vol': volume, + 'dev': os.path.realpath(rbd_dev_path)}) - return {'path': RBDConnector.get_rbd_device_name(pool, volume), + return {'path': rbd_dev_path, 'type': 'block'} rbd_handle = self._get_rbd_handle(connection_properties) diff --git a/os_brick/tests/initiator/connectors/test_rbd.py b/os_brick/tests/initiator/connectors/test_rbd.py index 1f11ca6ea..69b1b8f3f 100644 --- a/os_brick/tests/initiator/connectors/test_rbd.py +++ b/os_brick/tests/initiator/connectors/test_rbd.py @@ -186,6 +186,31 @@ class RBDConnectorTestCase(test_connector.ConnectorTestCase): 'type': 'block'} self.assertEqual(expected_info, device_info) + @mock.patch.object(priv_rootwrap, 'execute', return_value=None) + @mock.patch('os.path.exists') + @mock.patch('os.path.islink') + @mock.patch('os.path.realpath') + def test_connect_local_volume_dev_exist(self, mock_realpath, mock_islink, + mock_exists, mock_execute): + rbd_connector = rbd.RBDConnector(None, do_local_attach=True) + conn = {'name': 'pool/image', + 'auth_username': 'fake_user', + 'hosts': ['192.168.10.2'], + 'ports': ['6789']} + mock_realpath.return_value = '/dev/rbd0' + mock_islink.return_value = True + mock_exists.return_value = True + device_info = rbd_connector.connect_volume(conn) + execute_call1 = mock.call('which', 'rbd') + cmd = ['rbd', 'map', 'image', '--pool', 'pool', '--id', 'fake_user', + '--mon_host', '192.168.10.2:6789'] + execute_call2 = mock.call(*cmd, root_helper=None, run_as_root=True) + mock_execute.assert_has_calls([execute_call1]) + self.assertFalse(execute_call2 in mock_execute.mock_calls) + expected_info = {'path': '/dev/rbd/pool/image', + 'type': 'block'} + self.assertEqual(expected_info, device_info) + @mock.patch.object(priv_rootwrap, 'execute', return_value=None) def test_connect_local_volume_without_mons(self, mock_execute): rbd_connector = rbd.RBDConnector(None, do_local_attach=True)